summaryrefslogtreecommitdiffstats
path: root/lib/libaccess
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
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')
-rw-r--r--lib/libaccess/Makefile176
-rw-r--r--lib/libaccess/access_plhash.cpp65
-rw-r--r--lib/libaccess/access_plhash.h17
-rw-r--r--lib/libaccess/acl.tab.cpp1718
-rw-r--r--lib/libaccess/acl.tab.h44
-rw-r--r--lib/libaccess/acl.yy.cpp1995
-rw-r--r--lib/libaccess/aclbuild.cpp1360
-rw-r--r--lib/libaccess/aclcache.cpp579
-rw-r--r--lib/libaccess/aclcache.h27
-rw-r--r--lib/libaccess/aclerror.cpp246
-rw-r--r--lib/libaccess/acleval.cpp556
-rw-r--r--lib/libaccess/aclflush.cpp178
-rw-r--r--lib/libaccess/aclparse.cpp2241
-rw-r--r--lib/libaccess/aclpriv.h171
-rw-r--r--lib/libaccess/aclscan.h25
-rw-r--r--lib/libaccess/aclscan.l379
-rw-r--r--lib/libaccess/aclspace.cpp37
-rw-r--r--lib/libaccess/acltext.y957
-rw-r--r--lib/libaccess/acltools.cpp3457
-rw-r--r--lib/libaccess/aclutil.cpp223
-rw-r--r--lib/libaccess/aclutil.h25
-rw-r--r--lib/libaccess/attrec.cpp309
-rw-r--r--lib/libaccess/authdb.cpp339
-rw-r--r--lib/libaccess/avadb.c300
-rw-r--r--lib/libaccess/avaparse.y140
-rw-r--r--lib/libaccess/avapfile.c428
-rw-r--r--lib/libaccess/avascan.l106
-rw-r--r--lib/libaccess/las.h53
-rw-r--r--lib/libaccess/lasdns.cpp373
-rw-r--r--lib/libaccess/lasdns.h10
-rw-r--r--lib/libaccess/lasgroup.cpp164
-rw-r--r--lib/libaccess/lasip.cpp487
-rw-r--r--lib/libaccess/lasip.h13
-rw-r--r--lib/libaccess/lastod.cpp170
-rw-r--r--lib/libaccess/lasuser.cpp154
-rw-r--r--lib/libaccess/lcache.h23
-rw-r--r--lib/libaccess/ldapacl.cpp822
-rw-r--r--lib/libaccess/ldapauth.h42
-rw-r--r--lib/libaccess/leval.h18
-rw-r--r--lib/libaccess/lparse.h27
-rw-r--r--lib/libaccess/method.cpp163
-rw-r--r--lib/libaccess/nsadb.cpp582
-rw-r--r--lib/libaccess/nsamgmt.cpp1567
-rw-r--r--lib/libaccess/nsautherr.cpp126
-rw-r--r--lib/libaccess/nscert.cpp963
-rw-r--r--lib/libaccess/nsdb.cpp836
-rw-r--r--lib/libaccess/nsdbmgmt.cpp685
-rw-r--r--lib/libaccess/nseframe.cpp207
-rw-r--r--lib/libaccess/nsgmgmt.cpp434
-rw-r--r--lib/libaccess/nsgroup.cpp336
-rw-r--r--lib/libaccess/nslock.cpp268
-rw-r--r--lib/libaccess/nsumgmt.cpp456
-rw-r--r--lib/libaccess/nsuser.cpp309
-rw-r--r--lib/libaccess/oneeval.cpp1054
-rw-r--r--lib/libaccess/oneeval.h17
-rw-r--r--lib/libaccess/parse.h21
-rw-r--r--lib/libaccess/permhash.h79
-rw-r--r--lib/libaccess/register.cpp821
-rw-r--r--lib/libaccess/register.h98
-rw-r--r--lib/libaccess/symbols.cpp350
-rw-r--r--lib/libaccess/userauth.cpp12
-rw-r--r--lib/libaccess/usi.cpp371
-rw-r--r--lib/libaccess/usrcache.cpp657
-rw-r--r--lib/libaccess/utest.mk61
-rw-r--r--lib/libaccess/utest/.purify19
-rw-r--r--lib/libaccess/utest/Makefile119
-rw-r--r--lib/libaccess/utest/acl.dat12
-rw-r--r--lib/libaccess/utest/aclfile055
-rw-r--r--lib/libaccess/utest/aclfile111
-rw-r--r--lib/libaccess/utest/aclfile1013
-rw-r--r--lib/libaccess/utest/aclfile1111
-rw-r--r--lib/libaccess/utest/aclfile1211
-rw-r--r--lib/libaccess/utest/aclfile1311
-rw-r--r--lib/libaccess/utest/aclfile1411
-rw-r--r--lib/libaccess/utest/aclfile1511
-rw-r--r--lib/libaccess/utest/aclfile1611
-rw-r--r--lib/libaccess/utest/aclfile1711
-rw-r--r--lib/libaccess/utest/aclfile1819
-rw-r--r--lib/libaccess/utest/aclfile1914
-rw-r--r--lib/libaccess/utest/aclfile211
-rw-r--r--lib/libaccess/utest/aclfile311
-rw-r--r--lib/libaccess/utest/aclfile411
-rw-r--r--lib/libaccess/utest/aclfile511
-rw-r--r--lib/libaccess/utest/aclfile623
-rw-r--r--lib/libaccess/utest/aclfile711
-rw-r--r--lib/libaccess/utest/aclfile811
-rw-r--r--lib/libaccess/utest/aclfile911
-rw-r--r--lib/libaccess/utest/aclgrp010
-rw-r--r--lib/libaccess/utest/aclgrp110
-rw-r--r--lib/libaccess/utest/aclgrp210
-rw-r--r--lib/libaccess/utest/aclgrp310
-rw-r--r--lib/libaccess/utest/aclgrp410
-rw-r--r--lib/libaccess/utest/acltest.cpp796
-rw-r--r--lib/libaccess/utest/lasemail.cpp180
-rw-r--r--lib/libaccess/utest/onetest.cpp47
-rw-r--r--lib/libaccess/utest/shexp.cpp294
-rw-r--r--lib/libaccess/utest/shexp.h131
-rw-r--r--lib/libaccess/utest/test.ref234
-rw-r--r--lib/libaccess/utest/testmain.cpp52
-rw-r--r--lib/libaccess/utest/twotest.cpp57
-rw-r--r--lib/libaccess/utest/ustubs.cpp283
-rw-r--r--lib/libaccess/winnt.l762
-rw-r--r--lib/libaccess/winnt.v156
-rw-r--r--lib/libaccess/winnt.y793
-rw-r--r--lib/libaccess/wintab.h26
-rw-r--r--lib/libaccess/yy-sed21
106 files changed, 33248 insertions, 0 deletions
diff --git a/lib/libaccess/Makefile b/lib/libaccess/Makefile
new file mode 100644
index 00000000..1ed3b58a
--- /dev/null
+++ b/lib/libaccess/Makefile
@@ -0,0 +1,176 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Makefile for libaccess.a
+#
+MCOM_ROOT=../../..
+MODULE=LibAccess
+include ../../nsdefs.mk
+
+OBJDEST=$(OBJDIR)/lib/libaccess
+UTESTDEST=$(OBJDIR)/lib/libaccess/utest
+LEX=flex
+
+include ../../nsconfig.mk
+
+MCC_INCLUDE += $(ADMINUTIL_INCLUDE)
+
+ifeq ($(ARCH), WINNT)
+LIBS=$(OBJDIR)/lib/libaccess.lib
+CC=cl -nologo -MT
+VALUES=$(OBJDEST)/values.h
+else
+VALUES=
+LIBS=$(OBJDIR)/lib/libaccess.a
+endif
+
+all: $(OBJDEST) $(LIBS)
+
+$(OBJDEST):
+ mkdir -p $(OBJDEST)
+
+$(UTESTDEST):
+ mkdir -p $(UTESTDEST)
+
+OSOBJS =
+
+OBJS=$(addprefix $(OBJDEST)/, usi.o \
+ attrec.o \
+ nseframe.o \
+ nsdb.o \
+ nsdbmgmt.o \
+ nsuser.o \
+ nsumgmt.o \
+ nsgroup.o \
+ nsgmgmt.o \
+ nsadb.o \
+ nscert.o \
+ nsamgmt.o \
+ nsautherr.o \
+ symbols.o \
+ acltools.o \
+ aclutil.o \
+ aclcache.o \
+ aclflush.o \
+ authdb.o \
+ method.o \
+ ldapacl.o \
+ register.o \
+ lasdns.o \
+ lasip.o \
+ lastod.o \
+ usrcache.o \
+ lasgroup.o \
+ lasuser.o \
+ lasprogram.o \
+ aclspace.o \
+ acl.tab.o \
+ acl.yy.o \
+ acleval.o \
+ oneeval.o \
+ access_plhash.o \
+ aclparse.o \
+ aclbuild.o \
+ aclerror.o \
+ acladmin.o \
+ aclcgi.o \
+ $(OSOBJS) \
+ )
+
+#
+# AVA Mapping files. Currently not compiled in (FORTEZZA for reference only).
+#
+AVAMAPFILES = lex.yy.o y.tab.o avapfile.o avadb.o
+
+MODULE_CFLAGS=-I$(NSROOT)/include -DACL_LIB_INTERNAL $(TESTFLAGS)
+
+ifeq ($(LDAP_NO_LIBLCACHE),1)
+MODULE_CFLAGS+=-DNO_LIBLCACHE
+endif
+
+LOCAL_DEPS = $(LDAPSDK_DEP)
+
+$(LIBS): $(LOCAL_DEPS) $(OBJS)
+ rm -f $@
+ $(AR) $(OBJS)
+ $(RANLIB) $@
+
+include $(INCLUDE_DEPENDS)
+
+#
+# acl.tab.c acl.tab.h and acl.yy.c should not be generated by the build,
+# they are checked in and should be pulled from the tree by
+# default. The following rules are provided in case the grammar or
+# lexer needs changes.
+#
+
+#
+# Right now it's best to run yacc on a Solaris machine because the
+# /usr/lib/yaccpar makes the NT compiler happier. It should work on
+# other UNIX systems -- but that's what is checked in and tested.
+#
+yacc:
+ $(YACC) -d acltext.y
+ sed -f yy-sed y.tab.h > acl.tab.h
+ sed -f yy-sed y.tab.c > acl.tab.cpp
+ rm y.tab.h y.tab.c
+
+#
+# Flex generates a case insenitive lexer. It also provides mechanisms
+# that allow NSPR to replace it's standard IO routines. The standard UNIX
+# lex wants to use some stupid library! One would think that lex could
+# generate all the code it needs just like FLEX.
+#
+flex:
+ $(LEX) -i aclscan.l
+ sed -f yy-sed lex.yy.c > acl.yy.cpp
+ rm lex.yy.c
+
+#
+# more AVA mapping stuff, needs to be made to work with the other lexx/yacc
+# code added for 3.0
+#
+#ifeq ($(ARCH), WINNT)
+#$(OBJDEST)/y.tab.o: $(OBJDEST)/y.tab.c $(VALUES) $(OBJDEST)/y.tab.h
+# $(CC) -c $(CFLAGS) $(MCC_INCLUDE) -I$(OBJDEST) -I. $< -Fo$*.o
+#else
+#$(OBJDEST)/y.tab.o: $(OBJDEST)/y.tab.c $(OBJDEST)/y.tab.h
+# $(CC) -c $(CFLAGS) $(MCC_INCLUDE) -I. -o $*.o $<
+#endif
+#
+#ifeq ($(ARCH), WINNT)
+#$(OBJDEST)/y.tab.h: wintab.h
+# cp wintab.h $(OBJDEST)/y.tab.h
+#
+#$(OBJDEST)/y.tab.c: winnt.y
+# cp winnt.y $(OBJDEST)/y.tab.c
+#
+#$(OBJDEST)/values.h: winnt.v
+# cp winnt.v $(OBJDEST)/values.h
+#else
+#$(OBJDEST)/y.tab.h $(OBJDEST)/y.tab.c: avaparse.y
+# yacc -d avaparse.y
+# mv y.tab.h $(OBJDEST)/
+# mv y.tab.c $(OBJDEST)/
+#endif
+#
+#$(OBJDEST)/lex.yy.o: $(OBJDEST)/lex.yy.c $(OBJDEST)/y.tab.h
+#ifeq ($(ARCH), WINNT)
+# $(CC) -c $(CFLAGS) $(MCC_INCLUDE) -I$(OBJDEST) -I. $< -Fo$*.o
+#else
+# $(CC) -c $(CFLAGS) $(MCC_INCLUDE) -I. -o $*.o $<
+#endif
+#
+#ifeq ($(ARCH), WINNT)
+#$(OBJDEST)/lex.yy.c: winnt.l
+# cp winnt.l $(OBJDEST)/lex.yy.c
+#else
+#$(OBJDEST)/lex.yy.c: avascan.l
+# lex avascan.l
+# mv lex.yy.c $(OBJDEST)/
+#endif
diff --git a/lib/libaccess/access_plhash.cpp b/lib/libaccess/access_plhash.cpp
new file mode 100644
index 00000000..7666e95e
--- /dev/null
+++ b/lib/libaccess/access_plhash.cpp
@@ -0,0 +1,65 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ This file contains a function which augments the standard nspr PL_HashTable
+ api. The problem is that the hash table lookup function in the standard NSPR
+ actually modifies the hash table being searched, which means that it cannot be
+ used with read locks in a multi threaded environment. This function is a
+ lookup function which is guaranteed not to modify the hash table passed in,
+ so that it can be used with read locks.
+*/
+
+#include "plhash.h"
+
+/* prototypes */
+NSPR_BEGIN_EXTERN_C
+PR_IMPLEMENT(void *)
+ACL_HashTableLookup_const(PLHashTable *ht, const void *key);
+NSPR_END_EXTERN_C
+
+/*
+** Multiplicative hash, from Knuth 6.4.
+*/
+#define GOLDEN_RATIO 0x9E3779B9U
+
+PR_IMPLEMENT(PLHashEntry **)
+ACL_HashTableRawLookup_const(PLHashTable *ht, PLHashNumber keyHash, const void *key)
+{
+ PLHashEntry *he, **hep;
+ PLHashNumber h;
+
+#ifdef HASHMETER
+ ht->nlookups++;
+#endif
+ h = keyHash * GOLDEN_RATIO;
+ h >>= ht->shift;
+ hep = &ht->buckets[h];
+ while ((he = *hep) != 0) {
+ if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key)) {
+ return hep;
+ }
+ hep = &he->next;
+#ifdef HASHMETER
+ ht->nsteps++;
+#endif
+ }
+ return hep;
+}
+
+PR_IMPLEMENT(void *)
+ACL_HashTableLookup_const(PLHashTable *ht, const void *key)
+{
+ PLHashNumber keyHash;
+ PLHashEntry *he, **hep;
+
+ keyHash = (*ht->keyHash)(key);
+ hep = ACL_HashTableRawLookup_const(ht, keyHash, key);
+ if ((he = *hep) != 0) {
+ return he->value;
+ }
+ return 0;
+}
diff --git a/lib/libaccess/access_plhash.h b/lib/libaccess/access_plhash.h
new file mode 100644
index 00000000..fb1d86a1
--- /dev/null
+++ b/lib/libaccess/access_plhash.h
@@ -0,0 +1,17 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+NSPR_BEGIN_EXTERN_C
+/*
+ * access_plhash.cpp - supplement to NSPR plhash
+ */
+extern void *
+ACL_HashTableLookup_const(
+ void *ht, /* really a PLHashTable */
+ const void *key);
+
+NSPR_END_EXTERN_C
+
diff --git a/lib/libaccess/acl.tab.cpp b/lib/libaccess/acl.tab.cpp
new file mode 100644
index 00000000..bc17be3d
--- /dev/null
+++ b/lib/libaccess/acl.tab.cpp
@@ -0,0 +1,1718 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+# line 8 "acltext.y"
+#include <string.h>
+#include <netsite.h>
+#include <base/util.h>
+#include <base/plist.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/nserror.h>
+#include "parse.h"
+#include "aclscan.h"
+
+#define MAX_LIST_SIZE 255
+static ACLListHandle_t *curr_acl_list; /* current acl list */
+static ACLHandle_t *curr_acl; /* current acl */
+static ACLExprHandle_t *curr_expr; /* current expression */
+static PFlags_t pflags; /* current authorization flags */
+static char *curr_args_list[MAX_LIST_SIZE]; /* current args */
+static char *curr_user_list[MAX_LIST_SIZE]; /* current users v2 */
+static char *curr_ip_dns_list[MAX_LIST_SIZE]; /* current ip/dns v2 */
+static PList_t curr_auth_info; /* current authorization method */
+static int use_generic_rights; /* use generic rights for conversion */
+
+int acl_PushListHandle(ACLListHandle_t *handle)
+{
+ curr_acl_list = handle;
+ return(0);
+}
+
+static void
+acl_string_lower(char *s)
+{
+int ii;
+int len;
+
+ len = strlen(s);
+ for (ii = 0; ii < len; ii++)
+ s[ii] = tolower(s[ii]);
+
+ return;
+}
+
+static void
+acl_clear_args(char **args_list)
+{
+ args_list[0] = NULL;
+}
+
+static void
+acl_add_arg(char **args_list, char *arg)
+{
+ static int args_index;
+
+ if ( args_list[0] == NULL ) {
+ args_index = 0;
+ }
+ args_list[args_index] = arg;
+ args_index++;
+ args_list[args_index] = NULL;
+}
+
+static void
+acl_free_args(char **args_list)
+{
+ int ii;
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( args_list[ii] )
+ PERM_FREE(args_list[ii]);
+ else
+ break;
+ }
+}
+
+static int
+acl_set_args(ACLExprHandle_t *expr, char **args_list)
+{
+ int ii;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( args_list[ii] ) {
+ if ( ACL_ExprAddArg(NULL, expr, args_list[ii]) < 0 ) {
+ aclerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+ } else
+ break;
+ }
+ return(0);
+}
+
+static int
+acl_set_users(ACLExprHandle_t *expr, char **user_list)
+{
+ int ii;
+ int jj;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( user_list[ii] ) {
+ if ( ACL_ExprTerm(NULL, expr, "user", CMP_OP_EQ,
+ user_list[ii]) < 0 ) {
+ aclerror("ACL_ExprTerm() failed");
+ acl_free_args(user_list);
+ return(-1);
+ }
+ } else
+ break;
+ }
+
+ acl_free_args(user_list);
+
+ for (jj = 0; jj < ii - 1; jj++) {
+ if ( ACL_ExprOr(NULL, expr) < 0 ) {
+ aclerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+static int
+acl_set_users_or_groups(ACLExprHandle_t *expr, char **user_list)
+{
+ int ii;
+ int jj;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( user_list[ii] ) {
+ if ( ACL_ExprTerm(NULL, expr, "user", CMP_OP_EQ,
+ user_list[ii]) < 0 ) {
+ aclerror("ACL_ExprTerm() failed");
+ acl_free_args(user_list);
+ return(-1);
+ }
+ if ( ACL_ExprTerm(NULL, expr, "group", CMP_OP_EQ,
+ user_list[ii]) < 0 ) {
+ aclerror("ACL_ExprTerm() failed");
+ acl_free_args(user_list);
+ return(-1);
+ }
+ } else
+ break;
+ }
+
+ acl_free_args(user_list);
+
+ for (jj = 0; jj < (ii * 2) - 1; jj++) {
+ if ( ACL_ExprOr(NULL, expr) < 0 ) {
+ aclerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+static int
+acl_set_ip_dns(ACLExprHandle_t *expr, char **ip_dns)
+{
+ int ii;
+ int jj;
+ int len;
+ char *attr;
+ char *val;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( ip_dns[ii] ) {
+
+ attr = "ip";
+ val = ip_dns[ii];
+ len = strlen(val);
+
+ for (jj = 0; jj < len; jj++) {
+ if ( strchr("0123456789.*", val[jj]) == 0 ) {
+ attr = "dns";
+ break;
+ }
+ }
+
+ if ( ACL_ExprTerm(NULL, expr, attr, CMP_OP_EQ,
+ val) < 0 ) {
+ aclerror("ACL_ExprTerm() failed");
+ acl_free_args(ip_dns);
+ return(-1);
+ }
+
+ } else
+ break;
+ }
+
+ acl_free_args(ip_dns);
+
+ for (jj = 0; jj < ii - 1; jj++) {
+ if ( ACL_ExprOr(NULL, expr) < 0 ) {
+ aclerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+
+ return(0);
+}
+
+
+
+# line 223 "acltext.y"
+typedef union
+#ifdef __cplusplus
+ ACLSTYPE
+#endif
+ {
+ char *string;
+ int ival;
+} ACLSTYPE;
+# define ACL_ABSOLUTE_TOK 257
+# define ACL_ACL_TOK 258
+# define ACL_ALLOW_TOK 259
+# define ACL_ALWAYS_TOK 260
+# define ACL_AND_TOK 261
+# define ACL_AT_TOK 262
+# define ACL_AUTHENTICATE_TOK 263
+# define ACL_CONTENT_TOK 264
+# define ACL_DEFAULT_TOK 265
+# define ACL_DENY_TOK 266
+# define ACL_GROUP_TOK 267
+# define ACL_IN_TOK 268
+# define ACL_INHERIT_TOK 269
+# define ACL_NOT_TOK 270
+# define ACL_NULL_TOK 271
+# define ACL_OR_TOK 272
+# define ACL_QSTRING_TOK 273
+# define ACL_READ_TOK 274
+# define ACL_TERMINAL_TOK 275
+# define ACL_VARIABLE_TOK 276
+# define ACL_VERSION_TOK 277
+# define ACL_WRITE_TOK 278
+# define ACL_WITH_TOK 279
+# define ACL_EQ_TOK 280
+# define ACL_GE_TOK 281
+# define ACL_GT_TOK 282
+# define ACL_LE_TOK 283
+# define ACL_LT_TOK 284
+# define ACL_NE_TOK 285
+
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#else
+#include <netsite.h>
+#include <memory.h>
+#endif
+
+
+#ifdef __cplusplus
+
+#ifndef aclerror
+ void aclerror(const char *);
+#endif
+
+#ifndef acllex
+#ifdef __EXTERN_C__
+ extern "C" { int acllex(void); }
+#else
+ int acllex(void);
+#endif
+#endif
+ int acl_Parse(void);
+
+#endif
+#define aclclearin aclchar = -1
+#define aclerrok aclerrflag = 0
+extern int aclchar;
+extern int aclerrflag;
+ACLSTYPE acllval;
+ACLSTYPE aclval;
+typedef int acltabelem;
+#ifndef ACLMAXDEPTH
+#define ACLMAXDEPTH 150
+#endif
+#if ACLMAXDEPTH > 0
+int acl_acls[ACLMAXDEPTH], *acls = acl_acls;
+ACLSTYPE acl_aclv[ACLMAXDEPTH], *aclv = acl_aclv;
+#else /* user does initial allocation */
+int *acls;
+ACLSTYPE *aclv;
+#endif
+static int aclmaxdepth = ACLMAXDEPTH;
+# define ACLERRCODE 256
+
+# line 952 "acltext.y"
+
+acltabelem aclexca[] ={
+-1, 1,
+ 0, -1,
+ -2, 0,
+ };
+# define ACLNPROD 120
+# define ACLLAST 251
+acltabelem aclact[]={
+
+ 176, 177, 178, 180, 179, 181, 156, 109, 69, 53,
+ 160, 116, 76, 6, 185, 169, 118, 186, 170, 117,
+ 150, 78, 85, 149, 77, 18, 144, 29, 17, 86,
+ 28, 11, 3, 126, 10, 136, 140, 82, 89, 104,
+ 87, 101, 7, 129, 127, 171, 133, 79, 72, 40,
+ 132, 38, 102, 55, 108, 37, 172, 105, 39, 60,
+ 60, 107, 128, 63, 59, 45, 61, 61, 93, 23,
+ 46, 6, 131, 130, 158, 142, 137, 157, 125, 134,
+ 154, 147, 56, 122, 112, 30, 75, 94, 81, 111,
+ 139, 138, 88, 73, 165, 164, 155, 57, 50, 49,
+ 48, 27, 14, 41, 65, 58, 145, 97, 153, 146,
+ 98, 152, 120, 25, 184, 151, 119, 24, 99, 64,
+ 13, 32, 15, 21, 5, 175, 159, 106, 103, 8,
+ 100, 124, 84, 83, 66, 54, 52, 143, 80, 51,
+ 67, 90, 36, 35, 26, 34, 33, 22, 31, 20,
+ 135, 113, 62, 74, 96, 47, 92, 71, 44, 68,
+ 43, 70, 42, 95, 16, 91, 9, 4, 19, 12,
+ 2, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 110, 115, 114, 121, 123, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 95, 141, 0,
+ 0, 0, 0, 0, 0, 148, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 163, 0, 0, 0, 166,
+ 167, 168, 0, 0, 0, 0, 174, 0, 173, 0,
+ 161, 0, 0, 0, 118, 78, 162, 117, 77, 182,
+ 183 };
+acltabelem aclpact[]={
+
+ -245,-10000000,-10000000, -234, -187,-10000000, -242,-10000000,-10000000, 80,
+-10000000,-10000000, 43, -248, -189, 76, 69,-10000000,-10000000,-10000000,
+ -189,-10000000, 42, -246, -38, -248,-10000000, -208,-10000000,-10000000,
+ -195,-10000000,-10000000, -208, 41, 40, 39,-10000000,-10000000, -270,
+ -213, -43, 38,-10000000,-10000000, -199, -200,-10000000,-10000000,-10000000,
+-10000000, 79,-10000000,-10000000,-10000000, -271,-10000000, -195,-10000000, -220,
+-10000000,-10000000, -28, -221, -239,-10000000, -235, -238,-10000000,-10000000,
+-10000000, -28,-10000000,-10000000, -194,-10000000, -252,-10000000,-10000000,-10000000,
+ 66,-10000000,-10000000,-10000000, 78, -223, -218, -203,-10000000, -273,
+ -238,-10000000, -39, -29, 75, 68, -39, -40, -239, -243,
+-10000000, -231, -202,-10000000, -232, -184,-10000000, -185, -214, -227,
+-10000000,-10000000, -241,-10000000,-10000000,-10000000, -257, -240,-10000000,-10000000,
+ -252,-10000000, -250,-10000000, 65,-10000000,-10000000,-10000000,-10000000,-10000000,
+-10000000,-10000000,-10000000,-10000000, -44, -241, -253, 74, 67, 64,
+-10000000,-10000000, -45, 37, -274, -30, -243,-10000000,-10000000, 36,
+ 35,-10000000, -257, -257,-10000000, -250, -258,-10000000, -216,-10000000,
+ -30, -30, -280,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,
+-10000000, -30, -30, 73,-10000000, -259,-10000000,-10000000,-10000000,-10000000,
+-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000 };
+acltabelem aclpgo[]={
+
+ 0, 171, 170, 169, 168, 167, 124, 166, 122, 103,
+ 164, 162, 160, 158, 105, 157, 93, 156, 89, 154,
+ 153, 151, 86, 87, 91, 90, 76, 79, 150, 149,
+ 123, 147, 121, 146, 145, 143, 142, 141, 92, 140,
+ 139, 138, 75, 88, 137, 136, 104, 135, 134, 133,
+ 132, 131, 77, 130, 128, 127, 78, 74, 126, 125 };
+acltabelem aclr1[]={
+
+ 0, 1, 1, 3, 1, 2, 5, 5, 6, 7,
+ 7, 8, 8, 10, 10, 9, 9, 11, 11, 15,
+ 13, 13, 14, 14, 17, 12, 19, 12, 16, 16,
+ 20, 20, 23, 23, 22, 22, 21, 21, 21, 24,
+ 24, 25, 26, 26, 26, 26, 18, 28, 28, 27,
+ 27, 4, 29, 29, 30, 30, 31, 31, 32, 32,
+ 33, 33, 33, 37, 36, 39, 36, 38, 40, 34,
+ 41, 41, 43, 42, 42, 44, 44, 45, 35, 47,
+ 35, 48, 46, 49, 50, 50, 50, 50, 50, 50,
+ 50, 55, 55, 55, 55, 53, 53, 53, 53, 54,
+ 54, 54, 54, 51, 51, 56, 52, 52, 52, 57,
+ 57, 57, 58, 58, 59, 59, 59, 59, 59, 59 };
+acltabelem aclr2[]={
+
+ 0, 0, 2, 1, 10, 2, 2, 4, 17, 3,
+ 3, 2, 6, 3, 3, 4, 6, 2, 2, 1,
+ 8, 6, 3, 3, 1, 10, 1, 10, 7, 3,
+ 2, 6, 2, 6, 3, 3, 2, 2, 6, 3,
+ 3, 5, 2, 2, 6, 6, 7, 7, 7, 2,
+ 4, 2, 2, 4, 6, 4, 5, 5, 2, 4,
+ 4, 4, 4, 1, 10, 1, 8, 7, 1, 17,
+ 2, 6, 3, 4, 6, 7, 7, 1, 6, 1,
+ 6, 1, 5, 10, 0, 3, 5, 3, 5, 3,
+ 5, 3, 3, 5, 5, 3, 3, 5, 5, 3,
+ 3, 5, 5, 2, 6, 3, 2, 7, 7, 2,
+ 6, 5, 7, 7, 2, 2, 2, 2, 2, 2 };
+acltabelem aclchk[]={
+
+-10000000, -1, -2, 277, -5, -6, 258, 276, -6, -7,
+ 276, 273, -3, 40, 59, -8, -10, 276, 273, -4,
+ -29, -30, -31, 258, 41, 44, -30, 59, 276, 273,
+ 123, -8, -32, -33, -34, -35, -36, 263, 259, 266,
+ 257, -9, -11, -12, -13, 260, 265, -32, 59, 59,
+ 59, -40, -45, 279, -47, 266, 125, 59, -14, 263,
+ 259, 266, -14, 263, 40, -46, -48, -39, -46, 279,
+ -9, -15, 268, -16, -20, -22, 40, 276, 273, 268,
+ -41, -43, 276, -49, -50, 257, 264, 275, -38, 276,
+ -37, -16, -17, 262, -23, -22, -19, 41, 44, 40,
+ -53, 264, 275, -54, 257, 275, -55, 264, 257, 280,
+ -38, -18, 123, -21, -24, -25, 40, 276, 273, 41,
+ 44, -18, 123, -43, -51, -56, 276, 275, 264, 275,
+ 257, 257, 264, 273, -27, -28, 276, -26, -24, -25,
+ 276, -23, -42, -44, 276, 41, 44, 125, -27, 276,
+ 273, 41, 44, 44, 125, 59, 280, -52, -57, -58,
+ 40, 270, 276, -56, 59, 59, -26, -26, -42, 273,
+ 276, 261, 272, -52, -57, -59, 280, 281, 282, 284,
+ 283, 285, -52, -52, 41, 273, 276 };
+acltabelem acldef[]={
+
+ 1, -2, 2, 0, 5, 6, 0, 3, 7, 0,
+ 9, 10, 0, 0, 0, 0, 11, 13, 14, 4,
+ 51, 52, 0, 0, 0, 0, 53, 55, 56, 57,
+ 0, 12, 54, 58, 0, 0, 0, 68, 77, 79,
+ 0, 0, 0, 17, 18, 0, 0, 59, 60, 61,
+ 62, 0, 81, 65, 81, 0, 8, 15, 19, 0,
+ 22, 23, 0, 0, 0, 78, 84, 0, 80, 63,
+ 16, 0, 24, 21, 29, 30, 0, 34, 35, 26,
+ 0, 70, 72, 82, 0, 85, 87, 89, 66, 0,
+ 0, 20, 0, 0, 0, 32, 0, 0, 0, 0,
+ 86, 95, 96, 88, 99, 100, 90, 91, 92, 0,
+ 64, 25, 0, 28, 36, 37, 0, 39, 40, 31,
+ 0, 27, 0, 71, 0, 103, 105, 97, 98, 101,
+ 102, 93, 94, 67, 0, 49, 0, 0, 42, 43,
+ 41, 33, 0, 0, 0, 0, 0, 46, 50, 0,
+ 0, 38, 0, 0, 69, 73, 0, 83, 106, 109,
+ 0, 0, 0, 104, 47, 48, 44, 45, 74, 75,
+ 76, 0, 0, 0, 111, 0, 114, 115, 116, 117,
+ 118, 119, 107, 108, 110, 112, 113 };
+typedef struct
+#ifdef __cplusplus
+ acltoktype
+#endif
+{ char *t_name; int t_val; } acltoktype;
+#ifndef ACLDEBUG
+# define ACLDEBUG 0 /* don't allow debugging */
+#endif
+
+#if ACLDEBUG
+
+acltoktype acltoks[] =
+{
+ "ACL_ABSOLUTE_TOK", 257,
+ "ACL_ACL_TOK", 258,
+ "ACL_ALLOW_TOK", 259,
+ "ACL_ALWAYS_TOK", 260,
+ "ACL_AND_TOK", 261,
+ "ACL_AT_TOK", 262,
+ "ACL_AUTHENTICATE_TOK", 263,
+ "ACL_CONTENT_TOK", 264,
+ "ACL_DEFAULT_TOK", 265,
+ "ACL_DENY_TOK", 266,
+ "ACL_GROUP_TOK", 267,
+ "ACL_IN_TOK", 268,
+ "ACL_INHERIT_TOK", 269,
+ "ACL_NOT_TOK", 270,
+ "ACL_NULL_TOK", 271,
+ "ACL_OR_TOK", 272,
+ "ACL_QSTRING_TOK", 273,
+ "ACL_READ_TOK", 274,
+ "ACL_TERMINAL_TOK", 275,
+ "ACL_VARIABLE_TOK", 276,
+ "ACL_VERSION_TOK", 277,
+ "ACL_WRITE_TOK", 278,
+ "ACL_WITH_TOK", 279,
+ "ACL_EQ_TOK", 280,
+ "ACL_GE_TOK", 281,
+ "ACL_GT_TOK", 282,
+ "ACL_LE_TOK", 283,
+ "ACL_LT_TOK", 284,
+ "ACL_NE_TOK", 285,
+ "-unknown-", -1 /* ends search */
+};
+
+char * aclreds[] =
+{
+ "-no such reduction-",
+ "start : /* empty */",
+ "start : start_acl_v2",
+ "start : ACL_VERSION_TOK ACL_VARIABLE_TOK",
+ "start : ACL_VERSION_TOK ACL_VARIABLE_TOK ';' start_acl_v3",
+ "start_acl_v2 : acl_list_v2",
+ "acl_list_v2 : acl_v2",
+ "acl_list_v2 : acl_list_v2 acl_v2",
+ "acl_v2 : ACL_ACL_TOK acl_name_v2 '(' arg_list_v2 ')' '{' directive_list_v2 '}'",
+ "acl_name_v2 : ACL_VARIABLE_TOK",
+ "acl_name_v2 : ACL_QSTRING_TOK",
+ "arg_list_v2 : arg_v2",
+ "arg_list_v2 : arg_v2 ',' arg_list_v2",
+ "arg_v2 : ACL_VARIABLE_TOK",
+ "arg_v2 : ACL_QSTRING_TOK",
+ "directive_list_v2 : directive_v2 ';'",
+ "directive_list_v2 : directive_v2 ';' directive_list_v2",
+ "directive_v2 : auth_method_v2",
+ "directive_v2 : auth_statement_v2",
+ "auth_statement_v2 : ACL_ALWAYS_TOK auth_type_v2",
+ "auth_statement_v2 : ACL_ALWAYS_TOK auth_type_v2 host_spec_list_action_v2",
+ "auth_statement_v2 : ACL_DEFAULT_TOK auth_type_v2 host_spec_list_action_v2",
+ "auth_type_v2 : ACL_ALLOW_TOK",
+ "auth_type_v2 : ACL_DENY_TOK",
+ "auth_method_v2 : ACL_ALWAYS_TOK ACL_AUTHENTICATE_TOK ACL_IN_TOK",
+ "auth_method_v2 : ACL_ALWAYS_TOK ACL_AUTHENTICATE_TOK ACL_IN_TOK realm_definition_v2",
+ "auth_method_v2 : ACL_DEFAULT_TOK ACL_AUTHENTICATE_TOK ACL_IN_TOK",
+ "auth_method_v2 : ACL_DEFAULT_TOK ACL_AUTHENTICATE_TOK ACL_IN_TOK realm_definition_v2",
+ "host_spec_list_action_v2 : user_expr_v2 ACL_AT_TOK host_spec_list_v2",
+ "host_spec_list_action_v2 : user_expr_v2",
+ "user_expr_v2 : user_v2",
+ "user_expr_v2 : '(' user_list_v2 ')'",
+ "user_list_v2 : user_v2",
+ "user_list_v2 : user_v2 ',' user_list_v2",
+ "user_v2 : ACL_VARIABLE_TOK",
+ "user_v2 : ACL_QSTRING_TOK",
+ "host_spec_list_v2 : dns_spec_v2",
+ "host_spec_list_v2 : ip_spec_v2",
+ "host_spec_list_v2 : '(' dns_ip_spec_list_v2 ')'",
+ "dns_spec_v2 : ACL_VARIABLE_TOK",
+ "dns_spec_v2 : ACL_QSTRING_TOK",
+ "ip_spec_v2 : ACL_VARIABLE_TOK ACL_VARIABLE_TOK",
+ "dns_ip_spec_list_v2 : dns_spec_v2",
+ "dns_ip_spec_list_v2 : ip_spec_v2",
+ "dns_ip_spec_list_v2 : dns_spec_v2 ',' dns_ip_spec_list_v2",
+ "dns_ip_spec_list_v2 : ip_spec_v2 ',' dns_ip_spec_list_v2",
+ "realm_definition_v2 : '{' methods_list_v2 '}'",
+ "method_v2 : ACL_VARIABLE_TOK ACL_VARIABLE_TOK ';'",
+ "method_v2 : ACL_VARIABLE_TOK ACL_QSTRING_TOK ';'",
+ "methods_list_v2 : method_v2",
+ "methods_list_v2 : method_v2 methods_list_v2",
+ "start_acl_v3 : acl_list",
+ "acl_list : acl",
+ "acl_list : acl_list acl",
+ "acl : named_acl ';' body_list",
+ "acl : named_acl ';'",
+ "named_acl : ACL_ACL_TOK ACL_VARIABLE_TOK",
+ "named_acl : ACL_ACL_TOK ACL_QSTRING_TOK",
+ "body_list : body",
+ "body_list : body body_list",
+ "body : authenticate_statement ';'",
+ "body : authorization_statement ';'",
+ "body : deny_statement ';'",
+ "deny_statement : ACL_ABSOLUTE_TOK ACL_DENY_TOK ACL_WITH_TOK",
+ "deny_statement : ACL_ABSOLUTE_TOK ACL_DENY_TOK ACL_WITH_TOK deny_common",
+ "deny_statement : ACL_DENY_TOK ACL_WITH_TOK",
+ "deny_statement : ACL_DENY_TOK ACL_WITH_TOK deny_common",
+ "deny_common : ACL_VARIABLE_TOK ACL_EQ_TOK ACL_QSTRING_TOK",
+ "authenticate_statement : ACL_AUTHENTICATE_TOK",
+ "authenticate_statement : ACL_AUTHENTICATE_TOK '(' attribute_list ')' '{' parameter_list '}'",
+ "attribute_list : attribute",
+ "attribute_list : attribute_list ',' attribute",
+ "attribute : ACL_VARIABLE_TOK",
+ "parameter_list : parameter ';'",
+ "parameter_list : parameter ';' parameter_list",
+ "parameter : ACL_VARIABLE_TOK ACL_EQ_TOK ACL_QSTRING_TOK",
+ "parameter : ACL_VARIABLE_TOK ACL_EQ_TOK ACL_VARIABLE_TOK",
+ "authorization_statement : ACL_ALLOW_TOK",
+ "authorization_statement : ACL_ALLOW_TOK auth_common_action",
+ "authorization_statement : ACL_DENY_TOK",
+ "authorization_statement : ACL_DENY_TOK auth_common_action",
+ "auth_common_action : /* empty */",
+ "auth_common_action : auth_common",
+ "auth_common : flag_list '(' args_list ')' expression",
+ "flag_list : /* empty */",
+ "flag_list : ACL_ABSOLUTE_TOK",
+ "flag_list : ACL_ABSOLUTE_TOK content_static",
+ "flag_list : ACL_CONTENT_TOK",
+ "flag_list : ACL_CONTENT_TOK absolute_static",
+ "flag_list : ACL_TERMINAL_TOK",
+ "flag_list : ACL_TERMINAL_TOK content_absolute",
+ "content_absolute : ACL_CONTENT_TOK",
+ "content_absolute : ACL_ABSOLUTE_TOK",
+ "content_absolute : ACL_CONTENT_TOK ACL_ABSOLUTE_TOK",
+ "content_absolute : ACL_ABSOLUTE_TOK ACL_CONTENT_TOK",
+ "content_static : ACL_CONTENT_TOK",
+ "content_static : ACL_TERMINAL_TOK",
+ "content_static : ACL_CONTENT_TOK ACL_TERMINAL_TOK",
+ "content_static : ACL_TERMINAL_TOK ACL_CONTENT_TOK",
+ "absolute_static : ACL_ABSOLUTE_TOK",
+ "absolute_static : ACL_TERMINAL_TOK",
+ "absolute_static : ACL_ABSOLUTE_TOK ACL_TERMINAL_TOK",
+ "absolute_static : ACL_TERMINAL_TOK ACL_ABSOLUTE_TOK",
+ "args_list : arg",
+ "args_list : args_list ',' arg",
+ "arg : ACL_VARIABLE_TOK",
+ "expression : factor",
+ "expression : factor ACL_AND_TOK expression",
+ "expression : factor ACL_OR_TOK expression",
+ "factor : base_expr",
+ "factor : '(' expression ')'",
+ "factor : ACL_NOT_TOK factor",
+ "base_expr : ACL_VARIABLE_TOK relop ACL_QSTRING_TOK",
+ "base_expr : ACL_VARIABLE_TOK relop ACL_VARIABLE_TOK",
+ "relop : ACL_EQ_TOK",
+ "relop : ACL_GE_TOK",
+ "relop : ACL_GT_TOK",
+ "relop : ACL_LT_TOK",
+ "relop : ACL_LE_TOK",
+ "relop : ACL_NE_TOK",
+};
+#endif /* ACLDEBUG */
+
+
+/*
+** Skeleton parser driver for yacc output
+*/
+
+/*
+** yacc user known macros and defines
+*/
+#define ACLERROR goto aclerrlab
+#define ACLACCEPT return(0)
+#define ACLABORT return(1)
+#define ACLBACKUP( newtoken, newvalue )\
+{\
+ if ( aclchar >= 0 || ( aclr2[ acltmp ] >> 1 ) != 1 )\
+ {\
+ aclerror( "syntax error - cannot backup" );\
+ goto aclerrlab;\
+ }\
+ aclchar = newtoken;\
+ aclstate = *aclps;\
+ acllval = newvalue;\
+ goto aclnewstate;\
+}
+#define ACLRECOVERING() (!!aclerrflag)
+#define ACLNEW(type) PERM_MALLOC(sizeof(type) * aclnewmax)
+#define ACLCOPY(to, from, type) \
+ (type *) memcpy(to, (char *) from, aclnewmax * sizeof(type))
+#define ACLENLARGE( from, type) \
+ (type *) PERM_REALLOC((char *) from, aclnewmax * sizeof(type))
+#ifndef ACLDEBUG
+# define ACLDEBUG 1 /* make debugging available */
+#endif
+
+/*
+** user known globals
+*/
+int acldebug; /* set to 1 to get debugging */
+
+/*
+** driver internal defines
+*/
+#define ACLFLAG (-10000000)
+
+/*
+** global variables used by the parser
+*/
+ACLSTYPE *aclpv; /* top of value stack */
+int *aclps; /* top of state stack */
+
+int aclstate; /* current state */
+int acltmp; /* extra var (lasts between blocks) */
+
+int aclnerrs; /* number of errors */
+int aclerrflag; /* error recovery flag */
+int aclchar; /* current input token number */
+
+
+
+#ifdef ACLNMBCHARS
+#define ACLLEX() aclcvtok(acllex())
+/*
+** aclcvtok - return a token if i is a wchar_t value that exceeds 255.
+** If i<255, i itself is the token. If i>255 but the neither
+** of the 30th or 31st bit is on, i is already a token.
+*/
+#if defined(__STDC__) || defined(__cplusplus)
+int aclcvtok(int i)
+#else
+int aclcvtok(i) int i;
+#endif
+{
+ int first = 0;
+ int last = ACLNMBCHARS - 1;
+ int mid;
+ wchar_t j;
+
+ if(i&0x60000000){/*Must convert to a token. */
+ if( aclmbchars[last].character < i ){
+ return i;/*Giving up*/
+ }
+ while ((last>=first)&&(first>=0)) {/*Binary search loop*/
+ mid = (first+last)/2;
+ j = aclmbchars[mid].character;
+ if( j==i ){/*Found*/
+ return aclmbchars[mid].tvalue;
+ }else if( j<i ){
+ first = mid + 1;
+ }else{
+ last = mid -1;
+ }
+ }
+ /*No entry in the table.*/
+ return i;/* Giving up.*/
+ }else{/* i is already a token. */
+ return i;
+ }
+}
+#else/*!ACLNMBCHARS*/
+#define ACLLEX() acllex()
+#endif/*!ACLNMBCHARS*/
+
+/*
+** acl_Parse - return 0 if worked, 1 if syntax error not recovered from
+*/
+#if defined(__STDC__) || defined(__cplusplus)
+int acl_Parse(void)
+#else
+int acl_Parse()
+#endif
+{
+ register ACLSTYPE *aclpvt; /* top of value stack for $vars */
+
+#if defined(__cplusplus) || defined(lint)
+/*
+ hacks to please C++ and lint - goto's inside switch should never be
+ executed; aclpvt is set to 0 to avoid "used before set" warning.
+*/
+ static int __yaccpar_lint_hack__ = 0;
+ switch (__yaccpar_lint_hack__)
+ {
+ case 1: goto aclerrlab;
+ case 2: goto aclnewstate;
+ }
+ aclpvt = 0;
+#endif
+
+ /*
+ ** Initialize externals - acl_Parse may be called more than once
+ */
+ aclpv = &aclv[-1];
+ aclps = &acls[-1];
+ aclstate = 0;
+ acltmp = 0;
+ aclnerrs = 0;
+ aclerrflag = 0;
+ aclchar = -1;
+
+#if ACLMAXDEPTH <= 0
+ if (aclmaxdepth <= 0)
+ {
+ if ((aclmaxdepth = ACLEXPAND(0)) <= 0)
+ {
+ aclerror("yacc initialization error");
+ ACLABORT;
+ }
+ }
+#endif
+
+ {
+ register ACLSTYPE *acl_pv; /* top of value stack */
+ register int *acl_ps; /* top of state stack */
+ register int acl_state; /* current state */
+ register int acl_n; /* internal state number info */
+ goto aclstack; /* moved from 6 lines above to here to please C++ */
+
+ /*
+ ** get globals into registers.
+ ** branch to here only if ACLBACKUP was called.
+ */
+ aclnewstate:
+ acl_pv = aclpv;
+ acl_ps = aclps;
+ acl_state = aclstate;
+ goto acl_newstate;
+
+ /*
+ ** get globals into registers.
+ ** either we just started, or we just finished a reduction
+ */
+ aclstack:
+ acl_pv = aclpv;
+ acl_ps = aclps;
+ acl_state = aclstate;
+
+ /*
+ ** top of for (;;) loop while no reductions done
+ */
+ acl_stack:
+ /*
+ ** put a state and value onto the stacks
+ */
+#if ACLDEBUG
+ /*
+ ** if debugging, look up token value in list of value vs.
+ ** name pairs. 0 and negative (-1) are special values.
+ ** Note: linear search is used since time is not a real
+ ** consideration while debugging.
+ */
+ if ( acldebug )
+ {
+ register int acl_i;
+
+ printf( "State %d, token ", acl_state );
+ if ( aclchar == 0 )
+ printf( "end-of-file\n" );
+ else if ( aclchar < 0 )
+ printf( "-none-\n" );
+ else
+ {
+ for ( acl_i = 0; acltoks[acl_i].t_val >= 0;
+ acl_i++ )
+ {
+ if ( acltoks[acl_i].t_val == aclchar )
+ break;
+ }
+ printf( "%s\n", acltoks[acl_i].t_name );
+ }
+ }
+#endif /* ACLDEBUG */
+ if ( ++acl_ps >= &acls[ aclmaxdepth ] ) /* room on stack? */
+ {
+ /*
+ ** reallocate and recover. Note that pointers
+ ** have to be reset, or bad things will happen
+ */
+ int aclps_index = (acl_ps - acls);
+ int aclpv_index = (acl_pv - aclv);
+ int aclpvt_index = (aclpvt - aclv);
+ int aclnewmax;
+#ifdef ACLEXPAND
+ aclnewmax = ACLEXPAND(aclmaxdepth);
+#else
+ aclnewmax = 2 * aclmaxdepth; /* double table size */
+ if (aclmaxdepth == ACLMAXDEPTH) /* first time growth */
+ {
+ char *newacls = (char *)ACLNEW(int);
+ char *newaclv = (char *)ACLNEW(ACLSTYPE);
+ if (newacls != 0 && newaclv != 0)
+ {
+ acls = ACLCOPY(newacls, acls, int);
+ aclv = ACLCOPY(newaclv, aclv, ACLSTYPE);
+ }
+ else
+ aclnewmax = 0; /* failed */
+ }
+ else /* not first time */
+ {
+ acls = ACLENLARGE(acls, int);
+ aclv = ACLENLARGE(aclv, ACLSTYPE);
+ if (acls == 0 || aclv == 0)
+ aclnewmax = 0; /* failed */
+ }
+#endif
+ if (aclnewmax <= aclmaxdepth) /* tables not expanded */
+ {
+ aclerror( "yacc stack overflow" );
+ ACLABORT;
+ }
+ aclmaxdepth = aclnewmax;
+
+ acl_ps = acls + aclps_index;
+ acl_pv = aclv + aclpv_index;
+ aclpvt = aclv + aclpvt_index;
+ }
+ *acl_ps = acl_state;
+ *++acl_pv = aclval;
+
+ /*
+ ** we have a new state - find out what to do
+ */
+ acl_newstate:
+ if ( ( acl_n = aclpact[ acl_state ] ) <= ACLFLAG )
+ goto acldefault; /* simple state */
+#if ACLDEBUG
+ /*
+ ** if debugging, need to mark whether new token grabbed
+ */
+ acltmp = aclchar < 0;
+#endif
+ if ( ( aclchar < 0 ) && ( ( aclchar = ACLLEX() ) < 0 ) )
+ aclchar = 0; /* reached EOF */
+#if ACLDEBUG
+ if ( acldebug && acltmp )
+ {
+ register int acl_i;
+
+ printf( "Received token " );
+ if ( aclchar == 0 )
+ printf( "end-of-file\n" );
+ else if ( aclchar < 0 )
+ printf( "-none-\n" );
+ else
+ {
+ for ( acl_i = 0; acltoks[acl_i].t_val >= 0;
+ acl_i++ )
+ {
+ if ( acltoks[acl_i].t_val == aclchar )
+ break;
+ }
+ printf( "%s\n", acltoks[acl_i].t_name );
+ }
+ }
+#endif /* ACLDEBUG */
+ if ( ( ( acl_n += aclchar ) < 0 ) || ( acl_n >= ACLLAST ) )
+ goto acldefault;
+ if ( aclchk[ acl_n = aclact[ acl_n ] ] == aclchar ) /*valid shift*/
+ {
+ aclchar = -1;
+ aclval = acllval;
+ acl_state = acl_n;
+ if ( aclerrflag > 0 )
+ aclerrflag--;
+ goto acl_stack;
+ }
+
+ acldefault:
+ if ( ( acl_n = acldef[ acl_state ] ) == -2 )
+ {
+#if ACLDEBUG
+ acltmp = aclchar < 0;
+#endif
+ if ( ( aclchar < 0 ) && ( ( aclchar = ACLLEX() ) < 0 ) )
+ aclchar = 0; /* reached EOF */
+#if ACLDEBUG
+ if ( acldebug && acltmp )
+ {
+ register int acl_i;
+
+ printf( "Received token " );
+ if ( aclchar == 0 )
+ printf( "end-of-file\n" );
+ else if ( aclchar < 0 )
+ printf( "-none-\n" );
+ else
+ {
+ for ( acl_i = 0;
+ acltoks[acl_i].t_val >= 0;
+ acl_i++ )
+ {
+ if ( acltoks[acl_i].t_val
+ == aclchar )
+ {
+ break;
+ }
+ }
+ printf( "%s\n", acltoks[acl_i].t_name );
+ }
+ }
+#endif /* ACLDEBUG */
+ /*
+ ** look through exception table
+ */
+ {
+ register int *aclxi = aclexca;
+
+ while ( ( *aclxi != -1 ) ||
+ ( aclxi[1] != acl_state ) )
+ {
+ aclxi += 2;
+ }
+ while ( ( *(aclxi += 2) >= 0 ) &&
+ ( *aclxi != aclchar ) )
+ ;
+ if ( ( acl_n = aclxi[1] ) < 0 )
+ ACLACCEPT;
+ }
+ }
+
+ /*
+ ** check for syntax error
+ */
+ if ( acl_n == 0 ) /* have an error */
+ {
+ /* no worry about speed here! */
+ switch ( aclerrflag )
+ {
+ case 0: /* new error */
+ aclerror( "syntax error" );
+ goto skip_init;
+ aclerrlab:
+ /*
+ ** get globals into registers.
+ ** we have a user generated syntax type error
+ */
+ acl_pv = aclpv;
+ acl_ps = aclps;
+ acl_state = aclstate;
+ skip_init:
+ aclnerrs++;
+ /* FALLTHRU */
+ case 1:
+ case 2: /* incompletely recovered error */
+ /* try again... */
+ aclerrflag = 3;
+ /*
+ ** find state where "error" is a legal
+ ** shift action
+ */
+ while ( acl_ps >= acls )
+ {
+ acl_n = aclpact[ *acl_ps ] + ACLERRCODE;
+ if ( acl_n >= 0 && acl_n < ACLLAST &&
+ aclchk[aclact[acl_n]] == ACLERRCODE) {
+ /*
+ ** simulate shift of "error"
+ */
+ acl_state = aclact[ acl_n ];
+ goto acl_stack;
+ }
+ /*
+ ** current state has no shift on
+ ** "error", pop stack
+ */
+#if ACLDEBUG
+# define _POP_ "Error recovery pops state %d, uncovers state %d\n"
+ if ( acldebug )
+ printf( _POP_, *acl_ps,
+ acl_ps[-1] );
+# undef _POP_
+#endif
+ acl_ps--;
+ acl_pv--;
+ }
+ /*
+ ** there is no state on stack with "error" as
+ ** a valid shift. give up.
+ */
+ ACLABORT;
+ case 3: /* no shift yet; eat a token */
+#if ACLDEBUG
+ /*
+ ** if debugging, look up token in list of
+ ** pairs. 0 and negative shouldn't occur,
+ ** but since timing doesn't matter when
+ ** debugging, it doesn't hurt to leave the
+ ** tests here.
+ */
+ if ( acldebug )
+ {
+ register int acl_i;
+
+ printf( "Error recovery discards " );
+ if ( aclchar == 0 )
+ printf( "token end-of-file\n" );
+ else if ( aclchar < 0 )
+ printf( "token -none-\n" );
+ else
+ {
+ for ( acl_i = 0;
+ acltoks[acl_i].t_val >= 0;
+ acl_i++ )
+ {
+ if ( acltoks[acl_i].t_val
+ == aclchar )
+ {
+ break;
+ }
+ }
+ printf( "token %s\n",
+ acltoks[acl_i].t_name );
+ }
+ }
+#endif /* ACLDEBUG */
+ if ( aclchar == 0 ) /* reached EOF. quit */
+ ACLABORT;
+ aclchar = -1;
+ goto acl_newstate;
+ }
+ }/* end if ( acl_n == 0 ) */
+ /*
+ ** reduction by production acl_n
+ ** put stack tops, etc. so things right after switch
+ */
+#if ACLDEBUG
+ /*
+ ** if debugging, print the string that is the user's
+ ** specification of the reduction which is just about
+ ** to be done.
+ */
+ if ( acldebug )
+ printf( "Reduce by (%d) \"%s\"\n",
+ acl_n, aclreds[ acl_n ] );
+#endif
+ acltmp = acl_n; /* value to switch over */
+ aclpvt = acl_pv; /* $vars top of value stack */
+ /*
+ ** Look in goto table for next state
+ ** Sorry about using acl_state here as temporary
+ ** register variable, but why not, if it works...
+ ** If aclr2[ acl_n ] doesn't have the low order bit
+ ** set, then there is no action to be done for
+ ** this reduction. So, no saving & unsaving of
+ ** registers done. The only difference between the
+ ** code just after the if and the body of the if is
+ ** the goto acl_stack in the body. This way the test
+ ** can be made before the choice of what to do is needed.
+ */
+ {
+ /* length of production doubled with extra bit */
+ register int acl_len = aclr2[ acl_n ];
+
+ if ( !( acl_len & 01 ) )
+ {
+ acl_len >>= 1;
+ aclval = ( acl_pv -= acl_len )[1]; /* $$ = $1 */
+ acl_state = aclpgo[ acl_n = aclr1[ acl_n ] ] +
+ *( acl_ps -= acl_len ) + 1;
+ if ( acl_state >= ACLLAST ||
+ aclchk[ acl_state =
+ aclact[ acl_state ] ] != -acl_n )
+ {
+ acl_state = aclact[ aclpgo[ acl_n ] ];
+ }
+ goto acl_stack;
+ }
+ acl_len >>= 1;
+ aclval = ( acl_pv -= acl_len )[1]; /* $$ = $1 */
+ acl_state = aclpgo[ acl_n = aclr1[ acl_n ] ] +
+ *( acl_ps -= acl_len ) + 1;
+ if ( acl_state >= ACLLAST ||
+ aclchk[ acl_state = aclact[ acl_state ] ] != -acl_n )
+ {
+ acl_state = aclact[ aclpgo[ acl_n ] ];
+ }
+ }
+ /* save until reenter driver code */
+ aclstate = acl_state;
+ aclps = acl_ps;
+ aclpv = acl_pv;
+ }
+ /*
+ ** code supplied by user is placed in this switch
+ */
+ switch( acltmp )
+ {
+
+case 3:
+# line 266 "acltext.y"
+{
+ PERM_FREE(aclpvt[-0].string);
+ } break;
+case 8:
+# line 286 "acltext.y"
+{
+ acl_free_args(curr_args_list);
+ } break;
+case 9:
+# line 292 "acltext.y"
+{
+ curr_acl = ACL_AclNew(NULL, aclpvt[-0].string);
+ PERM_FREE(aclpvt[-0].string);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ aclerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ acl_clear_args(curr_args_list);
+ use_generic_rights = 0;
+ if (strstr(curr_acl->tag, "READ")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("read"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("execute"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("list"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("info"));
+ } if (strstr(curr_acl->tag, "WRITE")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("write"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("delete"));
+ }
+ } break;
+case 10:
+# line 314 "acltext.y"
+{
+ curr_acl = ACL_AclNew(NULL, aclpvt[-0].string);
+ PERM_FREE(aclpvt[-0].string);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ aclerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ acl_clear_args(curr_args_list);
+ use_generic_rights = 0;
+ if (strstr(curr_acl->tag, "READ")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("read"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("execute"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("list"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("info"));
+ } if (strstr(curr_acl->tag, "WRITE")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("write"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("delete"));
+ }
+ } break;
+case 13:
+# line 342 "acltext.y"
+{
+ char acl_tmp_arg[255];
+ char *acl_new_arg;
+
+ if (!use_generic_rights) {
+ acl_string_lower(aclpvt[-0].string);
+ strcpy(acl_tmp_arg, "http_");
+ strcat(acl_tmp_arg, aclpvt[-0].string);
+ PERM_FREE(aclpvt[-0].string);
+ acl_new_arg = PERM_STRDUP(acl_tmp_arg);
+ acl_add_arg(curr_args_list, acl_new_arg);
+ } else {
+ PERM_FREE(aclpvt[-0].string);
+ }
+ } break;
+case 14:
+# line 358 "acltext.y"
+{
+ if (!use_generic_rights) {
+ acl_add_arg(curr_args_list, aclpvt[-0].string);
+ } else {
+ PERM_FREE(aclpvt[-0].string);
+ }
+ } break;
+case 19:
+# line 376 "acltext.y"
+{
+ if ( ACL_ExprSetPFlags(NULL, curr_expr,
+ ACL_PFLAG_ABSOLUTE) < 0 ) {
+ aclerror("Could not set authorization processing flags");
+ return(-1);
+ }
+ } break;
+case 22:
+# line 388 "acltext.y"
+{
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_ALLOW) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ acl_clear_args(curr_user_list);
+ acl_clear_args(curr_ip_dns_list);
+ } break;
+case 23:
+# line 398 "acltext.y"
+{
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_DENY) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ acl_clear_args(curr_user_list);
+ acl_clear_args(curr_ip_dns_list);
+ } break;
+case 24:
+# line 411 "acltext.y"
+{
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_AUTH) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(auth) failed");
+ return(-1);
+ }
+ if ( ACL_ExprSetPFlags(NULL, curr_expr,
+ ACL_PFLAG_ABSOLUTE) < 0 ) {
+ aclerror("Could not set authorization processing flags");
+ return(-1);
+ }
+ curr_auth_info = PListCreate(NULL, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ if ( ACL_ExprAddAuthInfo(curr_expr, curr_auth_info) < 0 ) {
+ aclerror("Could not set authorization info");
+ return(-1);
+ }
+ } break;
+case 26:
+# line 430 "acltext.y"
+{
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_AUTH) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(auth) failed");
+ return(-1);
+ }
+ curr_auth_info = PListCreate(NULL, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ if ( ACL_ExprAddAuthInfo(curr_expr, curr_auth_info) < 0 ) {
+ aclerror("Could not set authorization info");
+ return(-1);
+ }
+ } break;
+case 28:
+# line 446 "acltext.y"
+{
+ if ( acl_set_users_or_groups(curr_expr, curr_user_list) < 0 ) {
+ aclerror("acl_set_users_or_groups() failed");
+ return(-1);
+ }
+
+ if ( acl_set_ip_dns(curr_expr, curr_ip_dns_list) < 0 ) {
+ aclerror("acl_set_ip_dns() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAnd(NULL, curr_expr) < 0 ) {
+ aclerror("ACL_ExprAnd() failed");
+ return(-1);
+ }
+
+ if ( acl_set_args(curr_expr, curr_args_list) < 0 ) {
+ aclerror("acl_set_args() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ } break;
+case 29:
+# line 473 "acltext.y"
+{
+ if ( acl_set_users_or_groups(curr_expr, curr_user_list) < 0 ) {
+ aclerror("acl_set_users_or_groups() failed");
+ return(-1);
+ }
+
+ if ( acl_set_args(curr_expr, curr_args_list) < 0 ) {
+ aclerror("acl_set_args() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ } break;
+case 34:
+# line 500 "acltext.y"
+{
+ acl_add_arg(curr_user_list, aclpvt[-0].string);
+ } break;
+case 35:
+# line 504 "acltext.y"
+{
+ acl_add_arg(curr_user_list, aclpvt[-0].string);
+ } break;
+case 39:
+# line 516 "acltext.y"
+{
+ acl_add_arg(curr_ip_dns_list, aclpvt[-0].string);
+ } break;
+case 40:
+# line 520 "acltext.y"
+{
+ acl_add_arg(curr_ip_dns_list, aclpvt[-0].string);
+ } break;
+case 41:
+# line 526 "acltext.y"
+{
+ char tmp_str[255];
+
+ util_sprintf(tmp_str, "%s+%s", aclpvt[-1].string, aclpvt[-0].string);
+ PERM_FREE(aclpvt[-1].string);
+ PERM_FREE(aclpvt[-0].string);
+ acl_add_arg(curr_ip_dns_list, PERM_STRDUP(tmp_str));
+ } break;
+case 46:
+# line 543 "acltext.y"
+{
+ if ( ACL_ExprAddArg(NULL, curr_expr, "user") < 0 ) {
+ aclerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAddArg(NULL, curr_expr, "group") < 0 ) {
+ aclerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ } break;
+case 47:
+# line 562 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if (strcmp(aclpvt[-2].string, "database") == 0) {
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-1].string);
+ } else {
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index(aclpvt[-2].string), aclpvt[-2].string, aclpvt[-1].string, NULL) < 0 ) {
+ }
+ PERM_FREE(aclpvt[-2].string);
+ }
+ } break;
+case 48:
+# line 575 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if (strcmp(aclpvt[-2].string, "database") == 0) {
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-1].string);
+ } else {
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index(aclpvt[-2].string), aclpvt[-2].string, aclpvt[-1].string, NULL) < 0 ) {
+ }
+ PERM_FREE(aclpvt[-2].string);
+ }
+ } break;
+case 56:
+# line 611 "acltext.y"
+{
+ curr_acl = ACL_AclNew(NULL, aclpvt[-0].string);
+ PERM_FREE(aclpvt[-0].string);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ aclerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ } break;
+case 57:
+# line 620 "acltext.y"
+{
+ curr_acl = ACL_AclNew(NULL, aclpvt[-0].string);
+ PERM_FREE(aclpvt[-0].string);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ aclerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ } break;
+case 63:
+# line 641 "acltext.y"
+{
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_RESPONSE) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(deny) failed");
+ return(-1);
+ }
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ if ( ACL_ExprSetPFlags(NULL, curr_expr,
+ ACL_PFLAG_ABSOLUTE) < 0 ) {
+ aclerror("Could not set deny processing flags");
+ return(-1);
+ }
+ } break;
+case 65:
+# line 659 "acltext.y"
+{
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_RESPONSE) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(deny) failed");
+ return(-1);
+ }
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ } break;
+case 67:
+# line 674 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if ( ACL_ExprSetDenyWith(NULL, curr_expr,
+ aclpvt[-2].string, aclpvt[-0].string) < 0 ) {
+ aclerror("ACL_ExprSetDenyWith() failed");
+ return(-1);
+ }
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-0].string);
+ } break;
+case 68:
+# line 687 "acltext.y"
+{
+ pflags = 0;
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_AUTH) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ curr_auth_info = PListCreate(NULL, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ if ( ACL_ExprAddAuthInfo(curr_expr, curr_auth_info) < 0 ) {
+ aclerror("Could not set authorization info");
+ return(-1);
+ }
+ } break;
+case 69:
+# line 701 "acltext.y"
+{
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ } break;
+case 72:
+# line 713 "acltext.y"
+{
+ acl_string_lower(aclpvt[-0].string);
+ if ( ACL_ExprAddArg(NULL, curr_expr, aclpvt[-0].string) < 0 ) {
+ aclerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+ PERM_FREE(aclpvt[-0].string);
+ } break;
+case 75:
+# line 728 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index(aclpvt[-2].string), aclpvt[-2].string, aclpvt[-0].string, NULL) < 0 ) {
+ }
+ PERM_FREE(aclpvt[-2].string);
+ } break;
+case 76:
+# line 736 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index(aclpvt[-2].string), aclpvt[-2].string, aclpvt[-0].string, NULL) < 0 ) {
+ }
+ PERM_FREE(aclpvt[-2].string);
+ } break;
+case 77:
+# line 746 "acltext.y"
+{
+ pflags = 0;
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_ALLOW) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ } break;
+case 79:
+# line 756 "acltext.y"
+{
+ pflags = 0;
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_DENY) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(deny) failed");
+ return(-1);
+ }
+ } break;
+case 81:
+# line 768 "acltext.y"
+{
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ } break;
+case 82:
+# line 775 "acltext.y"
+{
+ if ( ACL_ExprSetPFlags (NULL, curr_expr, pflags) < 0 ) {
+ aclerror("Could not set authorization processing flags");
+ return(-1);
+ }
+#ifdef DEBUG
+ if ( ACL_ExprDisplay(curr_expr) < 0 ) {
+ aclerror("ACL_ExprDisplay() failed");
+ return(-1);
+ }
+ printf("Parsed authorization.\n");
+#endif
+ } break;
+case 85:
+# line 795 "acltext.y"
+{
+ pflags = ACL_PFLAG_ABSOLUTE;
+ } break;
+case 86:
+# line 799 "acltext.y"
+{
+ pflags = ACL_PFLAG_ABSOLUTE;
+ } break;
+case 87:
+# line 803 "acltext.y"
+{
+ pflags = ACL_PFLAG_CONTENT;
+ } break;
+case 88:
+# line 807 "acltext.y"
+{
+ pflags = ACL_PFLAG_CONTENT;
+ } break;
+case 89:
+# line 811 "acltext.y"
+{
+ pflags = ACL_PFLAG_TERMINAL;
+ } break;
+case 90:
+# line 815 "acltext.y"
+{
+ pflags = ACL_PFLAG_TERMINAL;
+ } break;
+case 91:
+# line 821 "acltext.y"
+{
+ pflags |= ACL_PFLAG_CONTENT;
+ } break;
+case 92:
+# line 825 "acltext.y"
+{
+ pflags |= ACL_PFLAG_ABSOLUTE;
+ } break;
+case 93:
+# line 829 "acltext.y"
+{
+ pflags |= ACL_PFLAG_ABSOLUTE | ACL_PFLAG_CONTENT;
+ } break;
+case 94:
+# line 833 "acltext.y"
+{
+ pflags |= ACL_PFLAG_ABSOLUTE | ACL_PFLAG_CONTENT;
+ } break;
+case 95:
+# line 839 "acltext.y"
+{
+ pflags |= ACL_PFLAG_CONTENT;
+ } break;
+case 96:
+# line 843 "acltext.y"
+{
+ pflags |= ACL_PFLAG_TERMINAL;
+ } break;
+case 97:
+# line 847 "acltext.y"
+{
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_CONTENT;
+ } break;
+case 98:
+# line 851 "acltext.y"
+{
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_CONTENT;
+ } break;
+case 99:
+# line 857 "acltext.y"
+{
+ pflags |= ACL_PFLAG_ABSOLUTE;
+ } break;
+case 100:
+# line 861 "acltext.y"
+{
+ pflags |= ACL_PFLAG_TERMINAL;
+ } break;
+case 101:
+# line 865 "acltext.y"
+{
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_ABSOLUTE;
+ } break;
+case 102:
+# line 869 "acltext.y"
+{
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_ABSOLUTE;
+ } break;
+case 105:
+# line 879 "acltext.y"
+{
+ acl_string_lower(aclpvt[-0].string);
+ if ( ACL_ExprAddArg(NULL, curr_expr, aclpvt[-0].string) < 0 ) {
+ aclerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+ PERM_FREE( aclpvt[-0].string );
+ } break;
+case 107:
+# line 891 "acltext.y"
+{
+ if ( ACL_ExprAnd(NULL, curr_expr) < 0 ) {
+ aclerror("ACL_ExprAnd() failed");
+ return(-1);
+ }
+ } break;
+case 108:
+# line 898 "acltext.y"
+{
+ if ( ACL_ExprOr(NULL, curr_expr) < 0 ) {
+ aclerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ } break;
+case 111:
+# line 909 "acltext.y"
+{
+ if ( ACL_ExprNot(NULL, curr_expr) < 0 ) {
+ aclerror("ACL_ExprNot() failed");
+ return(-1);
+ }
+ } break;
+case 112:
+# line 918 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if ( ACL_ExprTerm(NULL, curr_expr,
+ aclpvt[-2].string, (CmpOp_t) aclpvt[-1].ival, aclpvt[-0].string) < 0 ) {
+ aclerror("ACL_ExprTerm() failed");
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-0].string);
+ return(-1);
+ }
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-0].string);
+ } break;
+case 113:
+# line 931 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if ( ACL_ExprTerm(NULL, curr_expr,
+ aclpvt[-2].string, (CmpOp_t) aclpvt[-1].ival, aclpvt[-0].string) < 0 ) {
+ aclerror("ACL_ExprTerm() failed");
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-0].string);
+ return(-1);
+ }
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-0].string);
+ } break;
+ }
+ goto aclstack; /* reset registers in driver code */
+}
+
diff --git a/lib/libaccess/acl.tab.h b/lib/libaccess/acl.tab.h
new file mode 100644
index 00000000..359f290a
--- /dev/null
+++ b/lib/libaccess/acl.tab.h
@@ -0,0 +1,44 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+typedef union
+#ifdef __cplusplus
+ ACLSTYPE
+#endif
+ {
+ char *string;
+ int ival;
+} ACLSTYPE;
+extern ACLSTYPE acllval;
+# define ACL_ABSOLUTE_TOK 257
+# define ACL_ACL_TOK 258
+# define ACL_ALLOW_TOK 259
+# define ACL_ALWAYS_TOK 260
+# define ACL_AND_TOK 261
+# define ACL_AT_TOK 262
+# define ACL_AUTHENTICATE_TOK 263
+# define ACL_CONTENT_TOK 264
+# define ACL_DEFAULT_TOK 265
+# define ACL_DENY_TOK 266
+# define ACL_GROUP_TOK 267
+# define ACL_IN_TOK 268
+# define ACL_INHERIT_TOK 269
+# define ACL_NOT_TOK 270
+# define ACL_NULL_TOK 271
+# define ACL_OR_TOK 272
+# define ACL_QSTRING_TOK 273
+# define ACL_READ_TOK 274
+# define ACL_TERMINAL_TOK 275
+# define ACL_VARIABLE_TOK 276
+# define ACL_VERSION_TOK 277
+# define ACL_WRITE_TOK 278
+# define ACL_WITH_TOK 279
+# define ACL_EQ_TOK 280
+# define ACL_GE_TOK 281
+# define ACL_GT_TOK 282
+# define ACL_LE_TOK 283
+# define ACL_LT_TOK 284
+# define ACL_NE_TOK 285
diff --git a/lib/libaccess/acl.yy.cpp b/lib/libaccess/acl.yy.cpp
new file mode 100644
index 00000000..90821330
--- /dev/null
+++ b/lib/libaccess/acl.yy.cpp
@@ -0,0 +1,1995 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define ACL_FLEX_MAJOR_VERSION 2
+#define ACL_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+
+/* Use prototypes in function declarations. */
+#define ACL_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define ACL_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define ACL_USE_PROTOS
+#define ACL_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define ACL_USE_CONST
+#define ACL_USE_PROTOS
+#endif
+
+#ifdef ACL_USE_CONST
+#define aclconst const
+#else
+#define aclconst
+#endif
+
+
+#ifdef ACL_USE_PROTOS
+#define ACL_PROTO(proto) proto
+#else
+#define ACL_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define ACL_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define ACL_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN acl_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The ACLSTATE alias is for lex
+ * compatibility.
+ */
+#define ACL_START ((acl_start - 1) / 2)
+#define ACLSTATE ACL_START
+
+/* Action number for EOF rule of a given start state. */
+#define ACL_STATE_EOF(state) (ACL_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define ACL_NEW_FILE aclrestart( aclin )
+
+#define ACL_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define ACL_BUF_SIZE 16384
+
+typedef struct acl_buffer_state *ACL_BUFFER_STATE;
+
+extern int aclleng;
+extern FILE *aclin, *aclout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * aclless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the aclless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define aclless(n) \
+ do \
+ { \
+ /* Undo effects of setting up acltext. */ \
+ *acl_cp = acl_hold_char; \
+ ACL_RESTORE_ACL_MORE_OFFSET \
+ acl_c_buf_p = acl_cp = acl_bp + n - ACL_MORE_ADJ; \
+ ACL_DO_BEFORE_ACTION; /* set up acltext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) aclunput( c, acltext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int acl_size_t;
+
+
+struct acl_buffer_state
+ {
+ FILE *acl_input_file;
+
+ char *acl_ch_buf; /* input buffer */
+ char *acl_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ acl_size_t acl_buf_size;
+
+ /* Number of characters read into acl_ch_buf, not including EOB
+ * characters.
+ */
+ int acl_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can PERM_REALLOC() it to grow it, and should PERM_FREE() it to
+ * delete it.
+ */
+ int acl_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int acl_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int acl_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int acl_fill_buffer;
+
+ int acl_buffer_status;
+#define ACL_BUFFER_NEW 0
+#define ACL_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as ACL_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via aclrestart()), so that the user can continue scanning by
+ * just pointing aclin at a new input file.
+ */
+#define ACL_BUFFER_EOF_PENDING 2
+ };
+
+static ACL_BUFFER_STATE acl_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define ACL_CURRENT_BUFFER acl_current_buffer
+
+
+/* acl_hold_char holds the character lost when acltext is formed. */
+static char acl_hold_char;
+
+static int acl_n_chars; /* number of characters read into acl_ch_buf */
+
+
+int aclleng;
+
+/* Points to current character in buffer. */
+static char *acl_c_buf_p = (char *) 0;
+static int acl_init = 1; /* whether we need to initialize */
+static int acl_start = 0; /* start state number */
+
+/* Flag which is used to allow aclwrap()'s to do buffer switches
+ * instead of setting up a fresh aclin. A bit of a hack ...
+ */
+static int acl_did_buffer_switch_on_eof;
+
+void aclrestart ACL_PROTO(( FILE *input_file ));
+
+void acl_switch_to_buffer ACL_PROTO(( ACL_BUFFER_STATE new_buffer ));
+void acl_load_buffer_state ACL_PROTO(( void ));
+ACL_BUFFER_STATE acl_create_buffer ACL_PROTO(( FILE *file, int size ));
+void acl_delete_buffer ACL_PROTO(( ACL_BUFFER_STATE b ));
+void acl_init_buffer ACL_PROTO(( ACL_BUFFER_STATE b, FILE *file ));
+void acl_flush_buffer ACL_PROTO(( ACL_BUFFER_STATE b ));
+#define ACL_FLUSH_BUFFER acl_flush_buffer( acl_current_buffer )
+
+ACL_BUFFER_STATE acl_scan_buffer ACL_PROTO(( char *base, acl_size_t size ));
+ACL_BUFFER_STATE acl_scan_string ACL_PROTO(( aclconst char *str ));
+ACL_BUFFER_STATE acl_scan_bytes ACL_PROTO(( aclconst char *bytes, int len ));
+
+static void *ACL_FLEX_ALLOC ACL_PROTO(( acl_size_t ));
+static void *ACL_FLEX_REALLOC ACL_PROTO(( void *, acl_size_t ));
+static void ACL_FLEX_FREE ACL_PROTO(( void * ));
+
+#define acl_new_buffer acl_create_buffer
+
+#define acl_set_interactive(is_interactive) \
+ { \
+ if ( ! acl_current_buffer ) \
+ acl_current_buffer = acl_create_buffer( aclin, ACL_BUF_SIZE ); \
+ acl_current_buffer->acl_is_interactive = is_interactive; \
+ }
+
+#define acl_set_bol(at_bol) \
+ { \
+ if ( ! acl_current_buffer ) \
+ acl_current_buffer = acl_create_buffer( aclin, ACL_BUF_SIZE ); \
+ acl_current_buffer->acl_at_bol = at_bol; \
+ }
+
+#define ACL_AT_BOL() (acl_current_buffer->acl_at_bol)
+
+typedef unsigned char ACL_CHAR;
+FILE *aclin = (FILE *) 0, *aclout = (FILE *) 0;
+typedef int acl_state_type;
+extern char *acltext;
+#define acltext_ptr acltext
+
+static acl_state_type acl_get_previous_state ACL_PROTO(( void ));
+static acl_state_type acl_try_NUL_trans ACL_PROTO(( acl_state_type current_state ));
+static int acl_get_next_buffer ACL_PROTO(( void ));
+static void acl_fatal_error ACL_PROTO(( aclconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up acltext.
+ */
+#define ACL_DO_BEFORE_ACTION \
+ acltext_ptr = acl_bp; \
+ aclleng = (int) (acl_cp - acl_bp); \
+ acl_hold_char = *acl_cp; \
+ *acl_cp = '\0'; \
+ acl_c_buf_p = acl_cp;
+
+#define ACL_NUM_RULES 30
+#define ACL_END_OF_BUFFER 31
+static aclconst short int acl_accept[104] =
+ { 0,
+ 0, 0, 31, 30, 2, 1, 30, 30, 3, 28,
+ 29, 25, 22, 24, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 2, 1, 27, 0, 4, 3, 29,
+ 26, 23, 29, 29, 29, 29, 9, 29, 29, 29,
+ 14, 29, 21, 29, 29, 29, 29, 6, 29, 29,
+ 20, 29, 29, 29, 29, 29, 19, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 13, 29, 29, 29,
+ 18, 29, 7, 29, 29, 29, 29, 29, 29, 29,
+ 29, 8, 29, 29, 29, 29, 29, 29, 29, 29,
+ 11, 12, 15, 29, 17, 5, 29, 16, 29, 29,
+
+ 29, 10, 0
+ } ;
+
+static aclconst int acl_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 5, 6, 1, 1, 1, 1, 7,
+ 7, 8, 1, 7, 8, 8, 1, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 1, 7, 9,
+ 10, 11, 1, 1, 12, 13, 14, 15, 16, 17,
+ 8, 18, 19, 8, 8, 20, 21, 22, 23, 8,
+ 8, 24, 25, 26, 27, 28, 29, 8, 30, 8,
+ 1, 1, 1, 1, 8, 1, 12, 13, 14, 15,
+
+ 16, 17, 8, 18, 19, 8, 8, 20, 21, 22,
+ 23, 8, 8, 24, 25, 26, 27, 28, 29, 8,
+ 30, 8, 7, 1, 7, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static aclconst int acl_meta[31] =
+ { 0,
+ 1, 1, 2, 1, 1, 1, 1, 3, 1, 1,
+ 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
+ } ;
+
+static aclconst short int acl_base[108] =
+ { 0,
+ 0, 0, 118, 119, 115, 0, 106, 28, 0, 119,
+ 0, 105, 119, 104, 21, 90, 96, 89, 87, 85,
+ 92, 91, 87, 103, 0, 119, 33, 119, 0, 0,
+ 119, 119, 79, 83, 17, 87, 0, 75, 78, 22,
+ 81, 72, 0, 73, 72, 69, 71, 0, 70, 80,
+ 0, 73, 64, 77, 58, 71, 0, 65, 60, 66,
+ 63, 53, 51, 64, 63, 51, 0, 53, 57, 56,
+ 0, 47, 0, 48, 50, 49, 50, 50, 46, 44,
+ 40, 0, 39, 38, 37, 36, 49, 38, 43, 39,
+ 0, 0, 0, 36, 0, 0, 36, 0, 33, 16,
+
+ 24, 0, 119, 48, 51, 54, 29
+ } ;
+
+static aclconst short int acl_def[108] =
+ { 0,
+ 103, 1, 103, 103, 103, 104, 103, 105, 106, 103,
+ 107, 103, 103, 103, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 103, 104, 103, 105, 103, 106, 107,
+ 103, 103, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+
+ 107, 107, 0, 103, 103, 103, 103
+ } ;
+
+static aclconst short int acl_nxt[150] =
+ { 0,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 11, 16, 17, 11, 11, 11, 18, 11,
+ 11, 19, 20, 11, 11, 21, 11, 22, 23, 11,
+ 28, 30, 28, 33, 34, 28, 49, 28, 54, 102,
+ 35, 101, 36, 55, 100, 50, 37, 38, 25, 99,
+ 25, 27, 27, 27, 29, 98, 29, 97, 96, 95,
+ 94, 93, 92, 91, 90, 89, 88, 87, 86, 85,
+ 84, 83, 82, 81, 80, 79, 78, 77, 76, 75,
+ 74, 73, 72, 71, 70, 69, 68, 67, 66, 65,
+ 64, 63, 62, 61, 60, 59, 58, 57, 56, 53,
+
+ 52, 51, 48, 47, 24, 46, 45, 44, 43, 42,
+ 41, 40, 39, 32, 31, 26, 24, 103, 3, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103
+ } ;
+
+static aclconst short int acl_chk[150] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 8, 107, 8, 15, 15, 27, 35, 27, 40, 101,
+ 15, 100, 15, 40, 99, 35, 15, 15, 104, 97,
+ 104, 105, 105, 105, 106, 94, 106, 90, 89, 88,
+ 87, 86, 85, 84, 83, 81, 80, 79, 78, 77,
+ 76, 75, 74, 72, 70, 69, 68, 66, 65, 64,
+ 63, 62, 61, 60, 59, 58, 56, 55, 54, 53,
+ 52, 50, 49, 47, 46, 45, 44, 42, 41, 39,
+
+ 38, 36, 34, 33, 24, 23, 22, 21, 20, 19,
+ 18, 17, 16, 14, 12, 7, 5, 3, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103
+ } ;
+
+static acl_state_type acl_last_accepting_state;
+static char *acl_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define aclmore() aclmore_used_but_not_detected
+#define ACL_MORE_ADJ 0
+#define ACL_RESTORE_ACL_MORE_OFFSET
+char *acltext;
+#line 1 "aclscan.l"
+#define INITIAL 0
+/*
+ * Lexical analyzer for ACL
+ */
+#line 6 "aclscan.l"
+#include "acl.tab.h" /* token codes */
+#include <base/file.h>
+#include <libaccess/acl.h>
+#include <libaccess/nserror.h>
+#include "aclpriv.h"
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <libaccess/aclerror.h>
+#ifdef XP_WIN32
+#include <io.h>
+#endif
+
+#include "parse.h"
+#include "aclscan.h"
+
+static int acl_scanner_input(char *buffer, int max_size);
+
+#define ACL_NEVER_INTERACTIVE 1
+#undef ACL_INPUT
+#define ACL_INPUT(buf, result, max) (result = acl_scanner_input(buf, max))
+
+static int acl_lineno;
+static int acl_tokenpos;
+static char acl_filename[500];
+static NSErr_t *acl_errp;
+static int acl_use_buffer;
+static char *acl_buffer;
+static int acl_buffer_length;
+static int acl_buffer_offset;
+static char *last_string;
+static SYS_FILE acl_prfd;
+
+
+#line 466 "acl.yy.cpp"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef ACL_SKIP_ACLWRAP
+#ifdef __cplusplus
+extern "C" int aclwrap ACL_PROTO(( void ));
+#else
+extern int aclwrap ACL_PROTO(( void ));
+#endif
+#endif
+
+#ifndef ACL_NO_UNPUT
+static void aclunput ACL_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef acltext_ptr
+static void acl_flex_strncpy ACL_PROTO(( char *, aclconst char *, int ));
+#endif
+
+#ifdef ACL_NEED_STRLEN
+static int acl_flex_strlen ACL_PROTO(( aclconst char * ));
+#endif
+
+#ifndef ACL_NO_INPUT
+#ifdef __cplusplus
+static int aclinput ACL_PROTO(( void ));
+#else
+static int input ACL_PROTO(( void ));
+#endif
+#endif
+
+#if ACL_STACK_USED
+static int acl_start_stack_ptr = 0;
+static int acl_start_stack_depth = 0;
+static int *acl_start_stack = 0;
+#ifndef ACL_NO_PUSH_STATE
+static void acl_push_state ACL_PROTO(( int new_state ));
+#endif
+#ifndef ACL_NO_POP_STATE
+static void acl_pop_state ACL_PROTO(( void ));
+#endif
+#ifndef ACL_NO_TOP_STATE
+static int acl_top_state ACL_PROTO(( void ));
+#endif
+
+#else
+#define ACL_NO_PUSH_STATE 1
+#define ACL_NO_POP_STATE 1
+#define ACL_NO_TOP_STATE 1
+#endif
+
+#ifdef ACL_MALLOC_DECL
+ACL_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef ACL_READ_BUF_SIZE
+#define ACL_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( acltext, aclleng, 1, aclout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or ACL_NULL,
+ * is returned in "result".
+ */
+#ifndef ACL_INPUT
+#define ACL_INPUT(buf,result,max_size) \
+ if ( acl_current_buffer->acl_is_interactive ) \
+ { \
+ int c = '*', n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( aclin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( aclin ) ) \
+ ACL_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else if ( ((result = fread( buf, 1, max_size, aclin )) == 0) \
+ && ferror( aclin ) ) \
+ ACL_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "aclterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef aclterminate
+#define aclterminate() return ACL_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef ACL_START_STACK_INCR
+#define ACL_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef ACL_FATAL_ERROR
+#define ACL_FATAL_ERROR(msg) acl_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef ACL_DECL
+#define ACL_DECL int acllex ACL_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after acltext and aclleng
+ * have been set up.
+ */
+#ifndef ACL_USER_ACTION
+#define ACL_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef ACL_BREAK
+#define ACL_BREAK break;
+#endif
+
+#define ACL_RULE_SETUP \
+ ACL_USER_ACTION
+
+ACL_DECL
+ {
+ register acl_state_type acl_current_state;
+ register char *acl_cp, *acl_bp;
+ register int acl_act;
+
+#line 47 "aclscan.l"
+
+
+#line 620 "acl.yy.cpp"
+
+ if ( acl_init )
+ {
+ acl_init = 0;
+
+#ifdef ACL_USER_INIT
+ ACL_USER_INIT;
+#endif
+
+ if ( ! acl_start )
+ acl_start = 1; /* first start state */
+
+ if ( ! aclin )
+ aclin = stdin;
+
+ if ( ! aclout )
+ aclout = stdout;
+
+ if ( ! acl_current_buffer )
+ acl_current_buffer =
+ acl_create_buffer( aclin, ACL_BUF_SIZE );
+
+ acl_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ acl_cp = acl_c_buf_p;
+
+ /* Support of acltext. */
+ *acl_cp = acl_hold_char;
+
+ /* acl_bp points to the position in acl_ch_buf of the start of
+ * the current run.
+ */
+ acl_bp = acl_cp;
+
+ acl_current_state = acl_start;
+acl_match:
+ do
+ {
+ register ACL_CHAR acl_c = acl_ec[ACL_SC_TO_UI(*acl_cp)];
+ if ( acl_accept[acl_current_state] )
+ {
+ acl_last_accepting_state = acl_current_state;
+ acl_last_accepting_cpos = acl_cp;
+ }
+ while ( acl_chk[acl_base[acl_current_state] + acl_c] != acl_current_state )
+ {
+ acl_current_state = (int) acl_def[acl_current_state];
+ if ( acl_current_state >= 104 )
+ acl_c = acl_meta[(unsigned int) acl_c];
+ }
+ acl_current_state = acl_nxt[acl_base[acl_current_state] + (unsigned int) acl_c];
+ ++acl_cp;
+ }
+ while ( acl_base[acl_current_state] != 119 );
+
+acl_find_action:
+ acl_act = acl_accept[acl_current_state];
+ if ( acl_act == 0 )
+ { /* have to back up */
+ acl_cp = acl_last_accepting_cpos;
+ acl_current_state = acl_last_accepting_state;
+ acl_act = acl_accept[acl_current_state];
+ }
+
+ ACL_DO_BEFORE_ACTION;
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( acl_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of ACL_DO_BEFORE_ACTION */
+ *acl_cp = acl_hold_char;
+ acl_cp = acl_last_accepting_cpos;
+ acl_current_state = acl_last_accepting_state;
+ goto acl_find_action;
+
+case 1:
+ACL_RULE_SETUP
+#line 49 "aclscan.l"
+{
+ acl_lineno++;
+ acl_tokenpos = 0;
+ aclless(1);
+ }
+ ACL_BREAK
+case 2:
+ACL_RULE_SETUP
+#line 55 "aclscan.l"
+;
+ ACL_BREAK
+case 3:
+ACL_RULE_SETUP
+#line 57 "aclscan.l"
+;
+ ACL_BREAK
+case ACL_STATE_EOF(INITIAL):
+#line 59 "aclscan.l"
+{
+ acllval.string = NULL;
+ last_string = acllval.string;
+ return(0);
+ }
+ ACL_BREAK
+case 4:
+ACL_RULE_SETUP
+#line 65 "aclscan.l"
+{
+ acllval.string = PERM_STRDUP( acltext+1 );
+ last_string = acllval.string;
+ if ( acllval.string[aclleng-2] != '"' )
+ fprintf(stderr, "Unterminated string\n") ;
+ else
+ acllval.string[aclleng-2] = '\0';
+ acl_tokenpos += aclleng;
+ return ACL_QSTRING_TOK;
+ }
+ ACL_BREAK
+case 5:
+ACL_RULE_SETUP
+#line 77 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_ABSOLUTE_TOK;
+ }
+ ACL_BREAK
+case 6:
+ACL_RULE_SETUP
+#line 83 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_ACL_TOK;
+ }
+ ACL_BREAK
+case 7:
+ACL_RULE_SETUP
+#line 89 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_ALLOW_TOK;
+ }
+ ACL_BREAK
+case 8:
+ACL_RULE_SETUP
+#line 95 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_ALWAYS_TOK;
+ }
+ ACL_BREAK
+case 9:
+ACL_RULE_SETUP
+#line 101 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_AT_TOK;
+ }
+ ACL_BREAK
+case 10:
+ACL_RULE_SETUP
+#line 107 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_AUTHENTICATE_TOK;
+ }
+ ACL_BREAK
+case 11:
+ACL_RULE_SETUP
+#line 113 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_CONTENT_TOK;
+ }
+ ACL_BREAK
+case 12:
+ACL_RULE_SETUP
+#line 119 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_DEFAULT_TOK;
+ }
+ ACL_BREAK
+case 13:
+ACL_RULE_SETUP
+#line 125 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_DENY_TOK;
+ }
+ ACL_BREAK
+case 14:
+ACL_RULE_SETUP
+#line 131 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_IN_TOK;
+ }
+ ACL_BREAK
+case 15:
+ACL_RULE_SETUP
+#line 137 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_INHERIT_TOK;
+ }
+ ACL_BREAK
+case 16:
+ACL_RULE_SETUP
+#line 143 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_TERMINAL_TOK;
+ }
+ ACL_BREAK
+case 17:
+ACL_RULE_SETUP
+#line 149 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_VERSION_TOK;
+ }
+ ACL_BREAK
+case 18:
+ACL_RULE_SETUP
+#line 155 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_WITH_TOK;
+ }
+ ACL_BREAK
+case 19:
+ACL_RULE_SETUP
+#line 161 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_NOT_TOK;
+ }
+ ACL_BREAK
+case 20:
+ACL_RULE_SETUP
+#line 167 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = ACL_EXPR_OP_AND;
+ acl_tokenpos += aclleng;
+ return ACL_AND_TOK;
+ }
+ ACL_BREAK
+case 21:
+ACL_RULE_SETUP
+#line 174 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = ACL_EXPR_OP_OR;
+ acl_tokenpos += aclleng;
+ return ACL_OR_TOK;
+ }
+ ACL_BREAK
+case 22:
+ACL_RULE_SETUP
+#line 181 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = CMP_OP_EQ;
+ acl_tokenpos += aclleng;
+ return ACL_EQ_TOK;
+ }
+ ACL_BREAK
+case 23:
+ACL_RULE_SETUP
+#line 188 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = CMP_OP_GE;
+ acl_tokenpos += aclleng;
+ return ACL_GE_TOK;
+ }
+ ACL_BREAK
+case 24:
+ACL_RULE_SETUP
+#line 195 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = CMP_OP_GT;
+ acl_tokenpos += aclleng;
+ return ACL_GT_TOK;
+ }
+ ACL_BREAK
+case 25:
+ACL_RULE_SETUP
+#line 202 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = CMP_OP_LT;
+ acl_tokenpos += aclleng;
+ return ACL_LT_TOK;
+ }
+ ACL_BREAK
+case 26:
+ACL_RULE_SETUP
+#line 209 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = CMP_OP_LE;
+ acl_tokenpos += aclleng;
+ return ACL_LE_TOK;
+ }
+ ACL_BREAK
+case 27:
+ACL_RULE_SETUP
+#line 216 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = CMP_OP_NE;
+ acl_tokenpos += aclleng;
+ return ACL_NE_TOK;
+ }
+ ACL_BREAK
+case 28:
+ACL_RULE_SETUP
+#line 223 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return acltext[0];
+ }
+ ACL_BREAK
+case 29:
+ACL_RULE_SETUP
+#line 229 "aclscan.l"
+{
+ acl_tokenpos += aclleng;
+ acllval.string = PERM_STRDUP( acltext );
+ last_string = acllval.string;
+ return ACL_VARIABLE_TOK;
+ }
+ ACL_BREAK
+case 30:
+ACL_RULE_SETUP
+#line 235 "aclscan.l"
+ECHO;
+ ACL_BREAK
+#line 983 "acl.yy.cpp"
+
+ case ACL_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int acl_amount_of_matched_text = (int) (acl_cp - acltext_ptr) - 1;
+
+ /* Undo the effects of ACL_DO_BEFORE_ACTION. */
+ *acl_cp = acl_hold_char;
+ ACL_RESTORE_ACL_MORE_OFFSET
+
+ if ( acl_current_buffer->acl_buffer_status == ACL_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed aclin at a new source and called
+ * acllex(). If so, then we have to assure
+ * consistency between acl_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ acl_n_chars = acl_current_buffer->acl_n_chars;
+ acl_current_buffer->acl_input_file = aclin;
+ acl_current_buffer->acl_buffer_status = ACL_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for acl_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since acl_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( acl_c_buf_p <= &acl_current_buffer->acl_ch_buf[acl_n_chars] )
+ { /* This was really a NUL. */
+ acl_state_type acl_next_state;
+
+ acl_c_buf_p = acltext_ptr + acl_amount_of_matched_text;
+
+ acl_current_state = acl_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * acl_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ acl_next_state = acl_try_NUL_trans( acl_current_state );
+
+ acl_bp = acltext_ptr + ACL_MORE_ADJ;
+
+ if ( acl_next_state )
+ {
+ /* Consume the NUL. */
+ acl_cp = ++acl_c_buf_p;
+ acl_current_state = acl_next_state;
+ goto acl_match;
+ }
+
+ else
+ {
+ acl_cp = acl_c_buf_p;
+ goto acl_find_action;
+ }
+ }
+
+ else switch ( acl_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ acl_did_buffer_switch_on_eof = 0;
+
+ if ( aclwrap() )
+ {
+ /* Note: because we've taken care in
+ * acl_get_next_buffer() to have set up
+ * acltext, we can now set up
+ * acl_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * ACL_NULL, it'll still work - another
+ * ACL_NULL will get returned.
+ */
+ acl_c_buf_p = acltext_ptr + ACL_MORE_ADJ;
+
+ acl_act = ACL_STATE_EOF(ACL_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! acl_did_buffer_switch_on_eof )
+ ACL_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ acl_c_buf_p =
+ acltext_ptr + acl_amount_of_matched_text;
+
+ acl_current_state = acl_get_previous_state();
+
+ acl_cp = acl_c_buf_p;
+ acl_bp = acltext_ptr + ACL_MORE_ADJ;
+ goto acl_match;
+
+ case EOB_ACT_LAST_MATCH:
+ acl_c_buf_p =
+ &acl_current_buffer->acl_ch_buf[acl_n_chars];
+
+ acl_current_state = acl_get_previous_state();
+
+ acl_cp = acl_c_buf_p;
+ acl_bp = acltext_ptr + ACL_MORE_ADJ;
+ goto acl_find_action;
+ }
+ break;
+ }
+
+ default:
+ ACL_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of acllex */
+
+
+/* acl_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int acl_get_next_buffer()
+ {
+ register char *dest = acl_current_buffer->acl_ch_buf;
+ register char *source = acltext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( acl_c_buf_p > &acl_current_buffer->acl_ch_buf[acl_n_chars + 1] )
+ ACL_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( acl_current_buffer->acl_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( acl_c_buf_p - acltext_ptr - ACL_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (acl_c_buf_p - acltext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( acl_current_buffer->acl_buffer_status == ACL_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ acl_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ acl_current_buffer->acl_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef ACL_USES_REJECT
+ ACL_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ ACL_BUFFER_STATE b = acl_current_buffer;
+
+ int acl_c_buf_p_offset =
+ (int) (acl_c_buf_p - b->acl_ch_buf);
+
+ if ( b->acl_is_our_buffer )
+ {
+ int new_size = b->acl_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->acl_buf_size += b->acl_buf_size / 8;
+ else
+ b->acl_buf_size *= 2;
+
+ b->acl_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ ACL_FLEX_REALLOC( (void *) b->acl_ch_buf,
+ b->acl_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->acl_ch_buf = 0;
+
+ if ( ! b->acl_ch_buf )
+ ACL_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ acl_c_buf_p = &b->acl_ch_buf[acl_c_buf_p_offset];
+
+ num_to_read = acl_current_buffer->acl_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > ACL_READ_BUF_SIZE )
+ num_to_read = ACL_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ ACL_INPUT( (&acl_current_buffer->acl_ch_buf[number_to_move]),
+ acl_n_chars, num_to_read );
+ }
+
+ if ( acl_n_chars == 0 )
+ {
+ if ( number_to_move == ACL_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ aclrestart( aclin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ acl_current_buffer->acl_buffer_status =
+ ACL_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ acl_n_chars += number_to_move;
+ acl_current_buffer->acl_ch_buf[acl_n_chars] = ACL_END_OF_BUFFER_CHAR;
+ acl_current_buffer->acl_ch_buf[acl_n_chars + 1] = ACL_END_OF_BUFFER_CHAR;
+
+ acltext_ptr = &acl_current_buffer->acl_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* acl_get_previous_state - get the state just before the EOB char was reached */
+
+static acl_state_type acl_get_previous_state()
+ {
+ register acl_state_type acl_current_state;
+ register char *acl_cp;
+
+ acl_current_state = acl_start;
+
+ for ( acl_cp = acltext_ptr + ACL_MORE_ADJ; acl_cp < acl_c_buf_p; ++acl_cp )
+ {
+ register ACL_CHAR acl_c = (*acl_cp ? acl_ec[ACL_SC_TO_UI(*acl_cp)] : 1);
+ if ( acl_accept[acl_current_state] )
+ {
+ acl_last_accepting_state = acl_current_state;
+ acl_last_accepting_cpos = acl_cp;
+ }
+ while ( acl_chk[acl_base[acl_current_state] + acl_c] != acl_current_state )
+ {
+ acl_current_state = (int) acl_def[acl_current_state];
+ if ( acl_current_state >= 104 )
+ acl_c = acl_meta[(unsigned int) acl_c];
+ }
+ acl_current_state = acl_nxt[acl_base[acl_current_state] + (unsigned int) acl_c];
+ }
+
+ return acl_current_state;
+ }
+
+
+/* acl_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = acl_try_NUL_trans( current_state );
+ */
+
+#ifdef ACL_USE_PROTOS
+static acl_state_type acl_try_NUL_trans( acl_state_type acl_current_state )
+#else
+static acl_state_type acl_try_NUL_trans( acl_current_state )
+acl_state_type acl_current_state;
+#endif
+ {
+ register int acl_is_jam;
+ register char *acl_cp = acl_c_buf_p;
+
+ register ACL_CHAR acl_c = 1;
+ if ( acl_accept[acl_current_state] )
+ {
+ acl_last_accepting_state = acl_current_state;
+ acl_last_accepting_cpos = acl_cp;
+ }
+ while ( acl_chk[acl_base[acl_current_state] + acl_c] != acl_current_state )
+ {
+ acl_current_state = (int) acl_def[acl_current_state];
+ if ( acl_current_state >= 104 )
+ acl_c = acl_meta[(unsigned int) acl_c];
+ }
+ acl_current_state = acl_nxt[acl_base[acl_current_state] + (unsigned int) acl_c];
+ acl_is_jam = (acl_current_state == 103);
+
+ return acl_is_jam ? 0 : acl_current_state;
+ }
+
+
+#ifndef ACL_NO_UNPUT
+#ifdef ACL_USE_PROTOS
+static void aclunput( int c, register char *acl_bp )
+#else
+static void aclunput( c, acl_bp )
+int c;
+register char *acl_bp;
+#endif
+ {
+ register char *acl_cp = acl_c_buf_p;
+
+ /* undo effects of setting up acltext */
+ *acl_cp = acl_hold_char;
+
+ if ( acl_cp < acl_current_buffer->acl_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = acl_n_chars + 2;
+ register char *dest = &acl_current_buffer->acl_ch_buf[
+ acl_current_buffer->acl_buf_size + 2];
+ register char *source =
+ &acl_current_buffer->acl_ch_buf[number_to_move];
+
+ while ( source > acl_current_buffer->acl_ch_buf )
+ *--dest = *--source;
+
+ acl_cp += (int) (dest - source);
+ acl_bp += (int) (dest - source);
+ acl_n_chars = acl_current_buffer->acl_buf_size;
+
+ if ( acl_cp < acl_current_buffer->acl_ch_buf + 2 )
+ ACL_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--acl_cp = (char) c;
+
+
+ acltext_ptr = acl_bp;
+ acl_hold_char = *acl_cp;
+ acl_c_buf_p = acl_cp;
+ }
+#endif /* ifndef ACL_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int aclinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *acl_c_buf_p = acl_hold_char;
+
+ if ( *acl_c_buf_p == ACL_END_OF_BUFFER_CHAR )
+ {
+ /* acl_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( acl_c_buf_p < &acl_current_buffer->acl_ch_buf[acl_n_chars] )
+ /* This was really a NUL. */
+ *acl_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = acl_c_buf_p - acltext_ptr;
+ ++acl_c_buf_p;
+
+ switch ( acl_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( aclwrap() )
+ {
+ acl_c_buf_p = acltext_ptr + offset;
+ return EOF;
+ }
+
+ if ( ! acl_did_buffer_switch_on_eof )
+ ACL_NEW_FILE;
+#ifdef __cplusplus
+ return aclinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ acl_c_buf_p = acltext_ptr + offset;
+ break;
+
+ case EOB_ACT_LAST_MATCH:
+#ifdef __cplusplus
+ ACL_FATAL_ERROR(
+ "unexpected last match in aclinput()" );
+#else
+ ACL_FATAL_ERROR(
+ "unexpected last match in input()" );
+#endif
+ }
+ }
+ }
+
+ c = *(unsigned char *) acl_c_buf_p; /* cast for 8-bit char's */
+ *acl_c_buf_p = '\0'; /* preserve acltext */
+ acl_hold_char = *++acl_c_buf_p;
+
+
+ return c;
+ }
+
+
+#ifdef ACL_USE_PROTOS
+void aclrestart( FILE *input_file )
+#else
+void aclrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! acl_current_buffer )
+ acl_current_buffer = acl_create_buffer( aclin, ACL_BUF_SIZE );
+
+ acl_init_buffer( acl_current_buffer, input_file );
+ acl_load_buffer_state();
+ }
+
+
+#ifdef ACL_USE_PROTOS
+void acl_switch_to_buffer( ACL_BUFFER_STATE new_buffer )
+#else
+void acl_switch_to_buffer( new_buffer )
+ACL_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( acl_current_buffer == new_buffer )
+ return;
+
+ if ( acl_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *acl_c_buf_p = acl_hold_char;
+ acl_current_buffer->acl_buf_pos = acl_c_buf_p;
+ acl_current_buffer->acl_n_chars = acl_n_chars;
+ }
+
+ acl_current_buffer = new_buffer;
+ acl_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (aclwrap()) processing, but the only time this flag
+ * is looked at is after aclwrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ acl_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef ACL_USE_PROTOS
+void acl_load_buffer_state( void )
+#else
+void acl_load_buffer_state()
+#endif
+ {
+ acl_n_chars = acl_current_buffer->acl_n_chars;
+ acltext_ptr = acl_c_buf_p = acl_current_buffer->acl_buf_pos;
+ aclin = acl_current_buffer->acl_input_file;
+ acl_hold_char = *acl_c_buf_p;
+ }
+
+
+#ifdef ACL_USE_PROTOS
+ACL_BUFFER_STATE acl_create_buffer( FILE *file, int size )
+#else
+ACL_BUFFER_STATE acl_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ ACL_BUFFER_STATE b;
+
+ b = (ACL_BUFFER_STATE) ACL_FLEX_ALLOC( sizeof( struct acl_buffer_state ) );
+ if ( ! b )
+ ACL_FATAL_ERROR( "out of dynamic memory in acl_create_buffer()" );
+
+ b->acl_buf_size = size;
+
+ /* acl_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->acl_ch_buf = (char *) ACL_FLEX_ALLOC( b->acl_buf_size + 2 );
+ if ( ! b->acl_ch_buf )
+ ACL_FATAL_ERROR( "out of dynamic memory in acl_create_buffer()" );
+
+ b->acl_is_our_buffer = 1;
+
+ acl_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef ACL_USE_PROTOS
+void acl_delete_buffer( ACL_BUFFER_STATE b )
+#else
+void acl_delete_buffer( b )
+ACL_BUFFER_STATE b;
+#endif
+ {
+ if ( ! b )
+ return;
+
+ if ( b == acl_current_buffer )
+ acl_current_buffer = (ACL_BUFFER_STATE) 0;
+
+ if ( b->acl_is_our_buffer )
+ ACL_FLEX_FREE( (void *) b->acl_ch_buf );
+
+ ACL_FLEX_FREE( (void *) b );
+ }
+
+
+#ifndef ACL_ALWAYS_INTERACTIVE
+#ifndef ACL_NEVER_INTERACTIVE
+extern int isatty ACL_PROTO(( int ));
+#endif
+#endif
+
+#ifdef ACL_USE_PROTOS
+void acl_init_buffer( ACL_BUFFER_STATE b, FILE *file )
+#else
+void acl_init_buffer( b, file )
+ACL_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+ {
+ acl_flush_buffer( b );
+
+ b->acl_input_file = file;
+ b->acl_fill_buffer = 1;
+
+#if ACL_ALWAYS_INTERACTIVE
+ b->acl_is_interactive = 1;
+#else
+#if ACL_NEVER_INTERACTIVE
+ b->acl_is_interactive = 0;
+#else
+ b->acl_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+ }
+
+
+#ifdef ACL_USE_PROTOS
+void acl_flush_buffer( ACL_BUFFER_STATE b )
+#else
+void acl_flush_buffer( b )
+ACL_BUFFER_STATE b;
+#endif
+
+ {
+ b->acl_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->acl_ch_buf[0] = ACL_END_OF_BUFFER_CHAR;
+ b->acl_ch_buf[1] = ACL_END_OF_BUFFER_CHAR;
+
+ b->acl_buf_pos = &b->acl_ch_buf[0];
+
+ b->acl_at_bol = 1;
+ b->acl_buffer_status = ACL_BUFFER_NEW;
+
+ if ( b == acl_current_buffer )
+ acl_load_buffer_state();
+ }
+
+
+#ifndef ACL_NO_SCAN_BUFFER
+#ifdef ACL_USE_PROTOS
+ACL_BUFFER_STATE acl_scan_buffer( char *base, acl_size_t size )
+#else
+ACL_BUFFER_STATE acl_scan_buffer( base, size )
+char *base;
+acl_size_t size;
+#endif
+ {
+ ACL_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != ACL_END_OF_BUFFER_CHAR ||
+ base[size-1] != ACL_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (ACL_BUFFER_STATE) ACL_FLEX_ALLOC( sizeof( struct acl_buffer_state ) );
+ if ( ! b )
+ ACL_FATAL_ERROR( "out of dynamic memory in acl_scan_buffer()" );
+
+ b->acl_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->acl_buf_pos = b->acl_ch_buf = base;
+ b->acl_is_our_buffer = 0;
+ b->acl_input_file = 0;
+ b->acl_n_chars = b->acl_buf_size;
+ b->acl_is_interactive = 0;
+ b->acl_at_bol = 1;
+ b->acl_fill_buffer = 0;
+ b->acl_buffer_status = ACL_BUFFER_NEW;
+
+ acl_switch_to_buffer( b );
+
+ return b;
+ }
+#endif
+
+
+#ifndef ACL_NO_SCAN_STRING
+#ifdef ACL_USE_PROTOS
+ACL_BUFFER_STATE acl_scan_string( aclconst char *str )
+#else
+ACL_BUFFER_STATE acl_scan_string( str )
+aclconst char *str;
+#endif
+ {
+ int len;
+ for ( len = 0; str[len]; ++len )
+ ;
+
+ return acl_scan_bytes( str, len );
+ }
+#endif
+
+
+#ifndef ACL_NO_SCAN_BYTES
+#ifdef ACL_USE_PROTOS
+ACL_BUFFER_STATE acl_scan_bytes( aclconst char *bytes, int len )
+#else
+ACL_BUFFER_STATE acl_scan_bytes( bytes, len )
+aclconst char *bytes;
+int len;
+#endif
+ {
+ ACL_BUFFER_STATE b;
+ char *buf;
+ acl_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) ACL_FLEX_ALLOC( n );
+ if ( ! buf )
+ ACL_FATAL_ERROR( "out of dynamic memory in acl_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = ACL_END_OF_BUFFER_CHAR;
+
+ b = acl_scan_buffer( buf, n );
+ if ( ! b )
+ ACL_FATAL_ERROR( "bad buffer in acl_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->acl_is_our_buffer = 1;
+
+ return b;
+ }
+#endif
+
+
+#ifndef ACL_NO_PUSH_STATE
+#ifdef ACL_USE_PROTOS
+static void acl_push_state( int new_state )
+#else
+static void acl_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( acl_start_stack_ptr >= acl_start_stack_depth )
+ {
+ acl_size_t new_size;
+
+ acl_start_stack_depth += ACL_START_STACK_INCR;
+ new_size = acl_start_stack_depth * sizeof( int );
+
+ if ( ! acl_start_stack )
+ acl_start_stack = (int *) ACL_FLEX_ALLOC( new_size );
+
+ else
+ acl_start_stack = (int *) ACL_FLEX_REALLOC(
+ (void *) acl_start_stack, new_size );
+
+ if ( ! acl_start_stack )
+ ACL_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ acl_start_stack[acl_start_stack_ptr++] = ACL_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef ACL_NO_POP_STATE
+static void acl_pop_state()
+ {
+ if ( --acl_start_stack_ptr < 0 )
+ ACL_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(acl_start_stack[acl_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef ACL_NO_TOP_STATE
+static int acl_top_state()
+ {
+ return acl_start_stack[acl_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef ACL_EXIT_FAILURE
+#define ACL_EXIT_FAILURE 2
+#endif
+
+#ifdef ACL_USE_PROTOS
+static void acl_fatal_error( aclconst char msg[] )
+#else
+static void acl_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( ACL_EXIT_FAILURE );
+ }
+
+
+
+/* Redefine aclless() so it works in section 3 code. */
+
+#undef aclless
+#define aclless(n) \
+ do \
+ { \
+ /* Undo effects of setting up acltext. */ \
+ acltext[aclleng] = acl_hold_char; \
+ acl_c_buf_p = acltext + n; \
+ acl_hold_char = *acl_c_buf_p; \
+ *acl_c_buf_p = '\0'; \
+ aclleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef acltext_ptr
+#ifdef ACL_USE_PROTOS
+static void acl_flex_strncpy( char *s1, aclconst char *s2, int n )
+#else
+static void acl_flex_strncpy( s1, s2, n )
+char *s1;
+aclconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef ACL_NEED_STRLEN
+#ifdef ACL_USE_PROTOS
+static int acl_flex_strlen( aclconst char *s )
+#else
+static int acl_flex_strlen( s )
+aclconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef ACL_USE_PROTOS
+static void *ACL_FLEX_ALLOC( acl_size_t size )
+#else
+static void *ACL_FLEX_ALLOC( size )
+acl_size_t size;
+#endif
+ {
+ return (void *) PERM_MALLOC( size );
+ }
+
+#ifdef ACL_USE_PROTOS
+static void *ACL_FLEX_REALLOC( void *ptr, acl_size_t size )
+#else
+static void *ACL_FLEX_REALLOC( ptr, size )
+void *ptr;
+acl_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) PERM_REALLOC( (char *) ptr, size );
+ }
+
+#ifdef ACL_USE_PROTOS
+static void ACL_FLEX_FREE( void *ptr )
+#else
+static void ACL_FLEX_FREE( ptr )
+void *ptr;
+#endif
+ {
+ PERM_FREE( ptr );
+ }
+
+#if ACL_MAIN
+int main()
+ {
+ acllex();
+ return 0;
+ }
+#endif
+#line 235 "aclscan.l"
+
+
+void
+acl_detab(char *t, char *s)
+{
+ int ii;
+ int pos;
+ int len;
+
+ if (s == NULL || t == NULL)
+ return;
+
+ len = strlen(s);
+ pos = 0;
+ for (ii = 0; ii < len; ii++) {
+ if (s[ii] == '\t') {
+ t[pos] = ' ';
+ } else {
+ t[pos] = s[ii];
+ }
+ pos++;
+ }
+ t[pos] = '\0';
+ return;
+}
+
+void
+aclerror(const char *s)
+{
+char errorStr[256];
+
+#if defined(UTEST) || defined(ACL_COMPILER)
+ printf("ACL file: %s\n", acl_filename);
+ printf("Syntax error at line: %d, token: %s\n", acl_lineno, acltext);
+ if ( last_string )
+ PERM_FREE(last_string);
+#else
+ sprintf(errorStr, "%d", acl_lineno);
+ if (acltext) {
+ nserrGenerate(acl_errp, ACLERRPARSE, ACLERR1780, ACL_Program,
+ 3, acl_filename, errorStr, acltext);
+ } else {
+ nserrGenerate(acl_errp, ACLERRPARSE, ACLERR1780, ACL_Program,
+ 2, acl_filename, errorStr);
+ }
+ if ( last_string )
+ PERM_FREE(last_string);
+#endif
+
+}
+
+int
+acl_InitScanner(NSErr_t *errp, char *filename, char *buffer)
+{
+ acl_errp = errp;
+ acl_lineno = 1;
+ acl_use_buffer = (filename == NULL) ? 1 : 0 ;
+ if ( filename != NULL ) {
+ strcpy(acl_filename, filename);
+#ifdef UTEST
+ aclin = fopen(filename, "r");
+ if ( aclin == NULL ) {
+ return(-1);
+ }
+#else
+ acl_prfd = system_fopenRO(filename);
+ if ( acl_prfd == NULL ) {
+ return(-1);
+ }
+ aclin = (FILE *) acl_prfd;
+#endif
+ aclrestart(aclin);
+ } else if ( buffer != NULL ) {
+ strcpy(acl_filename, "internal-buffer");
+ acl_buffer_offset = 0;
+ acl_buffer_length = strlen(buffer);
+ acl_buffer = PERM_STRDUP(buffer);
+ if (acl_buffer == NULL)
+ return(-1);
+ aclrestart(NULL);
+ } else {
+ return(-1);
+ }
+ return(0);
+}
+
+int
+acl_EndScanner()
+{
+ acl_lineno = 0;
+ if ( acl_use_buffer) {
+ if ( acl_buffer )
+ PERM_FREE(acl_buffer);
+ } else if ( aclin ) {
+#ifdef UTEST
+ fclose(aclin);
+#else
+ if ( acl_prfd ) {
+ system_fclose(acl_prfd);
+ acl_prfd = NULL;
+ }
+#endif
+ aclin = NULL ;
+ }
+ return(0);
+}
+
+int
+aclwrap()
+{
+ return(1);
+}
+
+static int
+acl_scanner_input(char *buffer, int max_size)
+{
+ int len = 0;
+
+ if ( acl_use_buffer ) {
+ len = (acl_buffer_length > max_size) ? max_size :
+ acl_buffer_length;
+ memcpy(buffer, (const void *) &acl_buffer[acl_buffer_offset],
+ len);
+ acl_buffer_length -= len;
+ acl_buffer_offset += len;
+ }
+#ifdef UTEST
+ else if ( ((len = fread( buffer, 1, max_size, aclin )) == 0)
+ && ferror( aclin ) ) {
+ aclerror( "scanner input failed" );
+ }
+#else
+ else if ( (len = system_fread( acl_prfd, buffer, max_size)) < 0 ) {
+ aclerror( "scanner input failed" );
+ }
+#endif
+
+ return(len);
+}
diff --git a/lib/libaccess/aclbuild.cpp b/lib/libaccess/aclbuild.cpp
new file mode 100644
index 00000000..8c4647dc
--- /dev/null
+++ b/lib/libaccess/aclbuild.cpp
@@ -0,0 +1,1360 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (aclbuild.c)
+ *
+ * This module provides functions for building Access Control List
+ * (ACL) structures in memory.
+ *
+ */
+
+#include <assert.h>
+#include "base/systems.h"
+#include "netsite.h"
+#include "libaccess/nsauth.h"
+#include "libaccess/nsuser.h"
+#include "libaccess/nsgroup.h"
+#include "libaccess/nsadb.h"
+#include "libaccess/aclerror.h"
+#include "libaccess/aclstruct.h"
+#include "libaccess/aclbuild.h"
+#include "libaccess/aclparse.h"
+#include "libaccess/acleval.h"
+#include "libaccess/usi.h"
+
+char * ACL_Program = "NSACL"; /* ACL facility name */
+
+/*
+ * Description (accCreate)
+ *
+ * This function creates a new access control context, which
+ * provides context information for a set of ACL definitions.
+ * The caller also provides a handle for a symbol table to be
+ * used to store definitions of ACL and rights names.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * stp - symbol table handle (may be null)
+ * pacc - pointer to returned context handle
+ *
+ * Returns:
+ *
+ * If the context is created successfully, the return value is zero.
+ * Otherwise it is a negative error code (ACLERRxxxx - see aclerror.h),
+ * and an error frame will be generated if an error list is provided.
+ */
+
+int accCreate(NSErr_t * errp, void * stp, ACContext_t **pacc)
+{
+ ACContext_t * acc; /* pointer to new context */
+ int rv; /* result value */
+ int eid; /* error id */
+
+ *pacc = 0;
+
+ /* Do we need to create a symbol table? */
+ if (stp == 0) {
+
+ /* Yes, create a symbol table for ACL, rights, etc. names */
+ rv = symTableNew(&stp);
+ if (rv < 0) goto err_nomem1;
+ }
+
+ /* Allocate the context structure */
+ acc = (ACContext_t *)MALLOC(sizeof(ACContext_t));
+ if (acc == 0) goto err_nomem2;
+
+ /* Initialize it */
+ acc->acc_stp = stp;
+ acc->acc_acls = 0;
+ acc->acc_rights = 0;
+ acc->acc_refcnt = 0;
+
+ *pacc = acc;
+ return 0;
+
+ err_nomem1:
+ rv = ACLERRNOMEM;
+ eid = ACLERR3000;
+ goto err_ret;
+
+ err_nomem2:
+ rv = ACLERRNOMEM;
+ eid = ACLERR3020;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ return rv;
+}
+
+/*
+ * Description (accDestroy)
+ *
+ * This function destroys a set of ACL data structures referenced
+ * by a specified ACContext_t structure, including the ACContext_t
+ * itself.
+ *
+ * Arguments:
+ *
+ * acc - pointer to ACContext_t structure
+ * flags - bit flags (unused - must be zero)
+ */
+
+void accDestroy(ACContext_t * acc, int flags)
+{
+ ACL_t * acl;
+
+ if (acc != 0) {
+
+ /*
+ * First destroy all ACLs and any unnamed structures they reference.
+ * Note that aclDestroy() modifies the acc_acls list.
+ */
+ while ((acl = acc->acc_acls) != 0) {
+
+ aclDelete(acl);
+ }
+
+ /* If there's a symbol table, destroy everything it references */
+ if (acc->acc_stp != 0) {
+ symTableEnumerate(acc->acc_stp, 0, accDestroySym);
+
+ /* Destroy the symbol table itself */
+ symTableDestroy(acc->acc_stp, 0);
+ }
+
+ /* Free the ACContext_t structure */
+ FREE(acc);
+ }
+}
+
+/*
+ * Description (accDestroySym)
+ *
+ * This function is called to destroy the data structure associated
+ * with a specified Symbol_t symbol table entry. It examines the
+ * type of the symbol and calls the appropriate destructor.
+ *
+ * Arguments:
+ *
+ * sym - pointer to symbol table entry
+ * argp - unused - must be zero
+ *
+ * Returns:
+ *
+ * The return value is SYMENUMREMOVE.
+ */
+
+int accDestroySym(Symbol_t * sym, void * argp)
+{
+ switch (sym->sym_type) {
+ case ACLSYMACL: /* ACL */
+ aclDestroy((ACL_t *)sym);
+ break;
+
+ case ACLSYMRIGHT: /* access right */
+ {
+ RightDef_t * rdp = (RightDef_t *)sym;
+
+ if (rdp->rd_sym.sym_name != 0) {
+ FREE(rdp->rd_sym.sym_name);
+ }
+ FREE(rdp);
+ }
+ break;
+
+ case ACLSYMRDEF: /* access rights list */
+ aclRightSpecDestroy((RightSpec_t *)sym);
+ break;
+
+ case ACLSYMREALM: /* realm name */
+ aclRealmSpecDestroy((RealmSpec_t *)sym);
+ break;
+
+ case ACLSYMHOST: /* host specifications */
+ aclHostSpecDestroy((HostSpec_t *)sym);
+ break;
+
+ case ACLSYMUSER: /* user/group list */
+ aclUserSpecDestroy((UserSpec_t *)sym);
+ break;
+ }
+
+ return SYMENUMREMOVE;
+}
+
+/*
+ * Description (accReadFile)
+ *
+ * This function reads a specfied file containing ACL definitions
+ * and creates data structures in memory to represent the ACLs.
+ * The caller may provide a pointer to an existing ACContext_t
+ * structure which will serve as the root of the ACL structures,
+ * or else a new one will be created.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * aclfile - pointer to the ACL filename string
+ * pacc - value/result ACContext_t
+ *
+ * Returns:
+ *
+ * If the ACL file is read successfully, the return value is zero.
+ * Otherwise it is a negative error code (ACLERRxxxx - see aclerror.h),
+ * and an error frame will be generated if an error list is provided.
+ */
+
+int accReadFile(NSErr_t * errp, char * aclfile, ACContext_t **pacc)
+{
+ ACContext_t * acc = *pacc; /* pointer to ACL root structure */
+ ACLFile_t * acf = 0; /* pointer to ACL file handle */
+ void * stp = 0; /* ACL symbol table handle */
+ int rv; /* result value */
+ int eid; /* error id value */
+
+ /* Initialize the ACL parser */
+ rv = aclParseInit();
+ if (rv < 0) goto err_init;
+
+ /* Do we need to create a new ACContext_t structure? */
+ if (acc == 0) {
+
+ /* Yes, create a symbol table for ACL, rights, etc. names */
+ rv = symTableNew(&stp);
+ if (rv < 0) goto err_crsym;
+
+ /* Create a root structure for the ACLs, including the symbol table */
+ rv = accCreate(errp, stp, &acc);
+ if (rv < 0) goto err_ret2;
+ }
+
+ /* Open the ACL definition file */
+ rv = aclFileOpen(errp, aclfile, 0, &acf);
+ if (rv < 0) goto err_ret3;
+
+ /* Parse the ACL definitions, building ACL structures in memory */
+ rv = aclACLParse(errp, acf, acc, 0);
+ if (rv < 0) goto err_ret4;
+
+ aclFileClose(acf, 0);
+
+ if (pacc) *pacc = acc;
+
+ return rv;
+
+ err_init:
+ eid = ACLERR3100;
+ goto err_ret;
+
+ err_crsym:
+ eid = ACLERR3120;
+ rv = ACLERRNOMEM;
+ goto err_ret;
+
+ err_ret4:
+ aclFileClose(acf, 0);
+ err_ret3:
+ /* Destroy the ACContext_t if we just created it */
+ if (acc != *pacc) {
+ accDestroy(acc, 0);
+ }
+ goto err_ret;
+
+ err_ret2:
+ symTableDestroy(stp, 0);
+
+ err_ret:
+ return rv;
+}
+
+/*
+ * Description (aclAuthDNSAdd)
+ *
+ * This function adds a DNS name specification to the DNS filter
+ * associated with a given host list. The DNS name specification is
+ * either a fully-qualified domain name or a domain name suffix,
+ * indicated by a leading ".", e.g. (".mcom.com"). The name
+ * components included in a suffix must be complete. For example,
+ * ".scape.com" will not match names ending in ".netscape.com".
+ *
+ * Arguments:
+ *
+ * hspp - pointer to host list pointer
+ * dnsspec - DNS name or suffix string pointer
+ * fqdn - non-zero if dnsspec is fully qualified
+ *
+ * Returns:
+ *
+ * If successful, the return code is zero.
+ * An error is indicated by a negative return code (ACLERRxxxx
+ * - see aclerror.h).
+ */
+
+int aclAuthDNSAdd(HostSpec_t **hspp, char * dnsspec, int fqdn)
+{
+ HostSpec_t * hsp; /* host list pointer */
+ void * table; /* access control hash table pointer */
+ Symbol_t * sym; /* hash table entry pointer */
+ int rv; /* result value */
+
+ fqdn = (fqdn) ? 1 : 0;
+
+ /* Create the HostSpec_t if it doesn't exist */
+ hsp = *hspp;
+ if (hsp == 0) {
+
+ hsp = (HostSpec_t *)MALLOC(sizeof(HostSpec_t));
+ if (hsp == 0) goto err_nomem;
+ memset((void *)hsp, 0, sizeof(HostSpec_t));
+ hsp->hs_sym.sym_type = ACLSYMHOST;
+ }
+
+ /* Get pointer to hash table used for DNS filter */
+ table = hsp->hs_host.inh_dnf.dnf_hash;
+ if (table == 0) {
+
+ /* None there yet, so create one */
+ rv = symTableNew(&table);
+ if (rv < 0) goto punt;
+ hsp->hs_host.inh_dnf.dnf_hash = table;
+ }
+
+ /* See if the DNS spec is already in the table */
+ rv = symTableFindSym(table, dnsspec, fqdn, (void **)&sym);
+ if (rv < 0) {
+ if (rv != SYMERRNOSYM) goto punt;
+
+ /* It's not there, so add it */
+ sym = (Symbol_t *)MALLOC(sizeof(Symbol_t));
+ sym->sym_name = STRDUP(dnsspec);
+ sym->sym_type = fqdn;
+
+ rv = symTableAddSym(table, sym, (void *)sym);
+ if (rv < 0) goto err_nomem;
+ }
+
+ *hspp = hsp;
+
+ punt:
+ return rv;
+
+ err_nomem:
+ rv = ACLERRNOMEM;
+ goto punt;
+}
+
+/*
+ * Description (aclAuthIPAdd)
+ *
+ * This function adds an IP address specification to the IP filter
+ * associated with a given host list. The IP address specification
+ * consists of an IP host or network address and an IP netmask.
+ * For host addresses the netmask value is 255.255.255.255.
+ *
+ * Arguments:
+ *
+ * hspp - pointer to host list pointer
+ * ipaddr - IP host or network address
+ * netmask - IP netmask value
+ *
+ * Returns:
+ *
+ * If successful, the return code is zero.
+ * An error is indicated by a negative return code (ACLERRxxxx
+ * - see aclerror.h).
+ */
+
+int aclAuthIPAdd(HostSpec_t **hspp, IPAddr_t ipaddr, IPAddr_t netmask)
+{
+ HostSpec_t * hsp; /* host list pointer */
+ IPFilter_t * ipf; /* IP filter pointer */
+ IPNode_t * ipn; /* current node pointer */
+ IPNode_t * lastipn; /* last (lower) node pointer */
+ IPLeaf_t * leaf; /* leaf node pointer */
+ IPAddr_t bitmask; /* bit mask for current node */
+ int lastbit; /* number of last bit set in netmask */
+ int i; /* loop index */
+
+ /* Create the HostSpec_t if it doesn't exist */
+ hsp = *hspp;
+ if (hsp == 0) {
+
+ hsp = (HostSpec_t *)MALLOC(sizeof(HostSpec_t));
+ if (hsp == 0) goto err_nomem;
+ memset((void *)hsp, 0, sizeof(HostSpec_t));
+ hsp->hs_sym.sym_type = ACLSYMHOST;
+ }
+
+ ipf = &hsp->hs_host.inh_ipf;
+
+ /* If the filter doesn't have a root node yet, create it */
+ if (ipf->ipf_tree == 0) {
+
+ /* Allocate node */
+ ipn = (IPNode_t *)MALLOC(sizeof(IPNode_t));
+ if (ipn == 0) goto err_nomem;
+
+ /* Initialize it to test bit 31, but without any descendants */
+ ipn->ipn_type = IPN_NODE;
+ ipn->ipn_bit = 31;
+ ipn->ipn_parent = NULL;
+ ipn->ipn_clear = NULL;
+ ipn->ipn_set = NULL;
+ ipn->ipn_masked = NULL;
+
+ /* Set it as the root node in the radix tree */
+ ipf->ipf_tree = ipn;
+ }
+
+ /* First we search the tree to see where this IP specification fits */
+
+ lastipn = NULL;
+
+ for (ipn = ipf->ipf_tree; (ipn != NULL) && (ipn->ipn_type == IPN_NODE); ) {
+
+ /* Get a mask for the bit this node tests */
+ bitmask = (IPAddr_t) 1<<ipn->ipn_bit;
+
+ /* Save pointer to last internal node */
+ lastipn = ipn;
+
+ /* Is this a bit we care about? */
+ if (bitmask & netmask) {
+
+ /* Yes, get address of set or clear descendant pointer */
+ ipn = (bitmask & ipaddr) ? ipn->ipn_set : ipn->ipn_clear;
+ }
+ else {
+ /* No, get the address of the masked descendant pointer */
+ ipn = ipn->ipn_masked;
+ }
+ }
+
+ /* Did we end up at a leaf node? */
+ if (ipn == NULL) {
+
+ /*
+ * No, well, we need to find a leaf node if possible. The
+ * reason is that we need an IP address and netmask to compare
+ * to the IP address and netmask we're inserting. We know that
+ * they're the same up to the bit tested by the lastipn node,
+ * but we need to know the *highest* order bit that's different.
+ * Any leaf node below lastipn will do.
+ */
+
+ leaf = NULL;
+ ipn = lastipn;
+
+ while (ipn != NULL) {
+
+ /* Look for any non-null child link of the current node */
+ for (i = 0; i < IPN_NLINKS; ++i) {
+ if (ipn->ipn_links[i]) break;
+ }
+
+ /*
+ * Fail search for leaf if no non-null child link found.
+ * This should only happen on the root node of the tree
+ * when the tree is empty.
+ */
+ if (i >= IPN_NLINKS) {
+ assert(ipn == ipf->ipf_tree);
+ break;
+ }
+
+ /* Step to the child node */
+ ipn = ipn->ipn_links[i];
+
+ /* Is it a leaf? */
+ if (ipn->ipn_type == IPN_LEAF) {
+
+ /* Yes, search is over */
+ leaf = (IPLeaf_t *)ipn;
+ ipn = NULL;
+ break;
+ }
+ }
+ }
+ else {
+
+ /* Yes, loop terminated on a leaf node */
+ assert(ipn->ipn_type == IPN_LEAF);
+ leaf = (IPLeaf_t *)ipn;
+ }
+
+ /* Got a leaf yet? */
+ if (leaf != NULL) {
+
+ /* Combine the IP address and netmask differences */
+ bitmask = (leaf->ipl_ipaddr ^ ipaddr) | (leaf->ipl_netmask ^ netmask);
+
+ /* Are both the IP address and the netmask the same? */
+ if (bitmask == 0) {
+
+ /* Yes, duplicate entry */
+ return 0;
+ }
+
+ /* Find the bit number of the first different bit */
+ for (lastbit = 31;
+ (bitmask & 0x80000000) == 0; --lastbit, bitmask <<= 1) ;
+
+ /* Generate a bit mask with just that bit */
+ bitmask = (IPAddr_t) (1 << lastbit);
+
+ /*
+ * Go up the tree from lastipn, looking for an internal node
+ * that tests lastbit. Stop if we get to a node that tests
+ * a higher bit number first.
+ */
+ for (ipn = lastipn, lastipn = (IPNode_t *)leaf;
+ ipn != NULL; ipn = ipn->ipn_parent) {
+
+ if (ipn->ipn_bit >= lastbit) {
+ if (ipn->ipn_bit == lastbit) {
+ /* Need to add a leaf off ipn node */
+ lastipn = NULL;
+ }
+ break;
+ }
+ lastipn = ipn;
+ }
+
+ assert(ipn != NULL);
+ }
+ else {
+
+ /* Just hang a leaf off the lastipn node if no leaf */
+ ipn = lastipn;
+ lastipn = NULL;
+ lastbit = ipn->ipn_bit;
+ }
+
+ /*
+ * If lastipn is not NULL at this point, the new leaf will hang
+ * off an internal node inserted between the upper node, referenced
+ * by ipn, and the lower node, referenced by lastipn. The lower
+ * node may be an internal node or a leaf.
+ */
+ if (lastipn != NULL) {
+ IPNode_t * parent = ipn; /* parent of the new node */
+
+ assert((lastipn->ipn_type == IPN_LEAF) ||
+ (ipn == lastipn->ipn_parent));
+
+ /* Allocate space for the internal node */
+ ipn = (IPNode_t *)MALLOC(sizeof(IPNode_t));
+ if (ipn == NULL) goto err_nomem;
+
+ ipn->ipn_type = IPN_NODE;
+ ipn->ipn_bit = lastbit;
+ ipn->ipn_parent = parent;
+ ipn->ipn_clear = NULL;
+ ipn->ipn_set = NULL;
+ ipn->ipn_masked = NULL;
+
+ bitmask = (IPAddr_t) (1 << lastbit);
+
+ /*
+ * The values in the leaf we found above determine which
+ * descendant link of the new internal node will reference
+ * the subtree that we just ascended.
+ */
+ if (leaf->ipl_netmask & bitmask) {
+ if (leaf->ipl_ipaddr & bitmask) {
+ ipn->ipn_set = lastipn;
+ }
+ else {
+ ipn->ipn_clear = lastipn;
+ }
+ }
+ else {
+ ipn->ipn_masked = lastipn;
+ }
+
+ /* Allocate space for the new leaf */
+ leaf = (IPLeaf_t *)MALLOC(sizeof(IPLeaf_t));
+ if (leaf == NULL) {
+ FREE((void *)ipn);
+ goto err_nomem;
+ }
+
+ /* Insert internal node in tree */
+
+ /* First the downward link from the parent to the new node */
+ for (i = 0; i < IPN_NLINKS; ++i) {
+ if (parent->ipn_links[i] == lastipn) {
+ parent->ipn_links[i] = ipn;
+ break;
+ }
+ }
+
+ /* Then the upward link from the child (if it's not a leaf) */
+ if (lastipn->ipn_type == IPN_NODE) {
+ lastipn->ipn_parent = ipn;
+ }
+ }
+ else {
+ /* Allocate space for a leaf node only */
+ leaf = (IPLeaf_t *)MALLOC(sizeof(IPLeaf_t));
+ if (leaf == NULL) goto err_nomem;
+ }
+
+ /* Initialize the new leaf */
+ leaf->ipl_type = IPN_LEAF;
+ leaf->ipl_ipaddr = ipaddr;
+ leaf->ipl_netmask = netmask;
+
+ /*
+ * Select the appropriate descendant link of the internal node
+ * and point it at the new leaf.
+ */
+ bitmask = (IPAddr_t) (1 << ipn->ipn_bit);
+ if (bitmask & netmask) {
+ if (bitmask & ipaddr) {
+ assert(ipn->ipn_set == NULL);
+ ipn->ipn_set = (IPNode_t *)leaf;
+ }
+ else {
+ assert(ipn->ipn_clear == NULL);
+ ipn->ipn_clear = (IPNode_t *)leaf;
+ }
+ }
+ else {
+ assert(ipn->ipn_masked == NULL);
+ ipn->ipn_masked = (IPNode_t *)leaf;
+ }
+
+ *hspp = hsp;
+
+ /* Successful completion */
+ return 0;
+
+ err_nomem:
+ return ACLERRNOMEM;
+}
+
+/*
+ * Description (aclAuthNameAdd)
+ *
+ * This function adds a user or group to a given user list,
+ * in the context of a specified ACL that is being created. The
+ * name of the user or group is provided by the caller, and is
+ * looked up in the authentication database associated with the
+ * specified user list. The return value indicates whether the name
+ * matched a user or group name, and whether the corresponding user
+ * or group id was already present in the given user list.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * usp - pointer to user list specification
+ * rlm - pointer to current authentication realm
+ * name - pointer to user or group name string
+ *
+ * Returns:
+ *
+ * The return value is zero if the name is not found in the
+ * authentication database. If the name is found, the return value
+ * is a positive value containing bit flags:
+ *
+ * AIF_GROUP - name matches a group name
+ * AIF_USER - name matches a user name
+ * AIF_DUP - name was already represented in the
+ * specified user list
+ *
+ * An error is indicated by a negative return code (ACLERRxxxx
+ * - see aclerror.h), and an error frame will be generated if
+ * an error list is provided.
+ */
+
+int aclAuthNameAdd(NSErr_t * errp, UserSpec_t * usp,
+ Realm_t * rlm, char * name)
+{
+ void * guoptr; /* group or user object pointer */
+ int irv; /* insert result value */
+ int eid; /* error id */
+ int rv; /* result value */
+
+ /* There must be a realm specified in order to handle users */
+ if (rlm == 0) goto err_norealm;
+
+ /* Open the authentication database if it's not already */
+ if (rlm->rlm_authdb == 0) {
+
+ if (rlm->rlm_aif == 0) {
+ rlm->rlm_aif = &NSADB_AuthIF;
+ }
+
+ rv = (*rlm->rlm_aif->aif_open)(errp,
+ rlm->rlm_dbname, 0, &rlm->rlm_authdb);
+ if (rv < 0) goto err_open;
+ }
+
+ /* Look up the name in the authentication DB */
+ rv = (*rlm->rlm_aif->aif_findname)(errp, rlm->rlm_authdb, name,
+ (AIF_USER|AIF_GROUP), (void **)&guoptr);
+ if (rv <= 0) {
+ if (rv < 0) goto err_adb;
+
+ /* The name was not found in the database */
+ return 0;
+ }
+
+ /* The name was found. Was it a user name? */
+ if (rv == AIF_USER) {
+
+ /* Yes, add the user id to the user list */
+ irv = usiInsert(&usp->us_user.uu_user, ((UserObj_t *)guoptr)->uo_uid);
+ rv = ANA_USER;
+ }
+ else {
+
+ /* No, must be a group name. Add group id to an_groups list. */
+ irv = usiInsert(&usp->us_user.uu_group,
+ ((GroupObj_t *)guoptr)->go_gid);
+ rv = ANA_GROUP;
+ }
+
+ /* Examine the result of the insert operation */
+ if (irv <= 0) {
+ if (irv < 0) goto err_ins;
+
+ /* Id was already in the list */
+ rv |= ANA_DUP;
+ }
+
+ punt:
+ return rv;
+
+ err_norealm:
+ eid = ACLERR3400;
+ rv = ACLERRNORLM;
+ nserrGenerate(errp, rv, eid, ACL_Program, 1, name);
+ goto punt;
+
+ err_open:
+ eid = ACLERR3420;
+ rv = ACLERROPEN;
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 2, rlm->rlm_dbname, system_errmsg());
+ goto punt;
+
+ err_adb:
+ /* Error accessing authentication database. */
+ eid = ACLERR3440;
+ rv = ACLERRADB;
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, rlm->rlm_dbname, name);
+ goto punt;
+
+ err_ins:
+ /* Error on insert operation. Must be lack of memory. */
+ eid = ACLERR3460;
+ rv = ACLERRNOMEM;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ goto punt;
+}
+
+/*
+ * Description (aclClientsDirCreate)
+ *
+ * This function allocates and initializes a new ACClients_t
+ * ACL directive.
+ *
+ * Arguments:
+ *
+ * None.
+ *
+ * Returns:
+ *
+ * If successful, a pointer to the new ACClients_t is returned.
+ * A shortage of dynamic memory is indicated by a null return value.
+ */
+
+ACClients_t * aclClientsDirCreate()
+{
+ ACClients_t * acd; /* pointer to new ACClients_t */
+
+ acd = (ACClients_t *)MALLOC(sizeof(ACClients_t));
+ if (acd != 0) {
+ memset((void *)acd, 0, sizeof(ACClients_t));
+ }
+
+ return acd;
+}
+
+/*
+ * Description (aclCreate)
+ *
+ * This function creates a new ACL root structure. The caller
+ * specifies the name to be associated with the ACL. The ACL handle
+ * returned by this function is passed to other functions in this
+ * module when adding information to the ACL.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acc - pointer to an access control context
+ * aclname - pointer to ACL name string
+ * pacl - pointer to returned ACL handle
+ *
+ * Returns:
+ *
+ * The return value is zero if the ACL is created successfully.
+ * Otherwise it is a negative error code (ACLERRxxxx - see aclerror.h),
+ * and an error frame will be generated if an error list is provided.
+ */
+
+int aclCreate(NSErr_t * errp, ACContext_t * acc, char * aclname, ACL_t **pacl)
+{
+ ACL_t * acl; /* pointer to created ACL */
+ int rv; /* result value */
+ int eid; /* error id */
+
+ *pacl = 0;
+
+ /* Allocate the ACL_t structure */
+ acl = (ACL_t *) MALLOC(sizeof(ACL_t));
+ if (acl == 0) goto err_nomem;
+
+ /* Initialize the structure */
+ memset((void *)acl, 0, sizeof(ACL_t));
+ acl->acl_sym.sym_name = STRDUP(aclname);
+ acl->acl_sym.sym_type = ACLSYMACL;
+ acl->acl_acc = acc;
+ acl->acl_refcnt = 1;
+
+ /* Add it to the symbol table for the specified context */
+ rv = symTableAddSym(acc->acc_stp, &acl->acl_sym, (void *)acl);
+ if (rv < 0) goto err_addsym;
+
+ /* Add it to the list of ACLs for the specified context */
+ acl->acl_next = acc->acc_acls;
+ acc->acc_acls = acl;
+ acc->acc_refcnt += 1;
+
+ *pacl = acl;
+ return 0;
+
+ err_nomem:
+ rv = ACLERRNOMEM;
+ eid = ACLERR3200;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ goto done;
+
+ err_addsym:
+ FREE(acl);
+ rv = ACLERRDUPSYM;
+ eid = ACLERR3220;
+ nserrGenerate(errp, rv, eid, ACL_Program, 1, aclname);
+
+ done:
+ return rv;
+}
+
+/*
+ * Description (aclDestroy)
+ *
+ * This function destroys an ACL structure and its sub-structures.
+ * It does not free the ACContext_t referenced by the ACL.
+ *
+ * Arguments:
+ *
+ * acl - pointer to ACL_t structure
+ */
+
+void aclDestroy(ACL_t * acl)
+{
+ ACL_t **pacl; /* ACL list link pointer */
+ ACDirective_t * acd; /* ACL directive pointer */
+ ACDirective_t * nacd; /* next ACL directive pointer */
+
+ /* Is there an ACContext_t structure? */
+ if (acl->acl_acc != 0) {
+
+ /* Remove this ACL from the list in the ACContext_t structure */
+ for (pacl = &acl->acl_acc->acc_acls;
+ *pacl != 0; pacl = &(*pacl)->acl_next) {
+
+ if (*pacl == acl) {
+ *pacl = acl->acl_next;
+ acl->acl_acc->acc_refcnt -= 1;
+ break;
+ }
+ }
+ }
+
+ /* Destroy each ACL directive */
+ for (acd = acl->acl_dirf; acd != 0; acd = nacd) {
+ nacd = acd->acd_next;
+ aclDirectiveDestroy(acd);
+ }
+
+ /* Free the ACL rights list if it is unnamed */
+ if ((acl->acl_rights != 0) && (acl->acl_rights->rs_sym.sym_name == 0)) {
+ aclRightSpecDestroy(acl->acl_rights);
+ }
+
+ /* Free the ACL name string, if any */
+ if (acl->acl_sym.sym_name != 0) {
+ FREE(acl->acl_sym.sym_name);
+ }
+
+ /* Free the ACL itself */
+ FREE(acl);
+}
+
+/*
+ * Description (aclDelete)
+ *
+ * This function removes a specified ACL from the symbol table
+ * associated with its ACL context, and then destroys the ACL
+ * structure and any unnamed objects it references (other than
+ * the ACL context).
+ *
+ * Arguments:
+ *
+ * acl - pointer to the ACL
+ */
+
+void aclDelete(ACL_t * acl)
+{
+ ACContext_t * acc = acl->acl_acc;
+
+ if ((acc != 0) && (acl->acl_sym.sym_name != 0)) {
+ symTableRemoveSym(acc->acc_stp, &acl->acl_sym);
+ }
+
+ aclDestroy(acl);
+}
+
+/*
+ * Description (aclDirectiveAdd)
+ *
+ * This function adds a given directive to a specified ACL.
+ *
+ * Arguments:
+ *
+ * acl - pointer to the ACL
+ * acd - pointer to the directive to be added
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. An error is indicated
+ * by a negative return value.
+ */
+
+int aclDirectiveAdd(ACL_t * acl, ACDirective_t * acd)
+{
+ /* Add the directive to the end of the ACL's directive list */
+ acd->acd_next = 0;
+
+ if (acl->acl_dirl == 0) {
+ /* First entry in empty list */
+ acl->acl_dirf = acd;
+ }
+ else {
+ /* Append to end of list */
+ acl->acl_dirl->acd_next = acd;
+ }
+
+ acl->acl_dirl = acd;
+
+ return 0;
+}
+
+/*
+ * Description (aclDirectiveCreate)
+ *
+ * This function allocates and initializes a new ACDirective_t
+ * structure, representing an ACL directive.
+ *
+ * Arguments:
+ *
+ * None.
+ *
+ * Returns:
+ *
+ * If successful, the return value is a pointer to a new ACDirective_t.
+ * Otherwise the return value is null.
+ */
+
+ACDirective_t * aclDirectiveCreate()
+{
+ ACDirective_t * acd;
+
+ acd = (ACDirective_t *) MALLOC(sizeof(ACDirective_t));
+ if (acd != 0) {
+ memset((void *)acd, 0, sizeof(ACDirective_t));
+ }
+
+ return acd;
+}
+
+/*
+ * Description (aclDirectiveDestroy)
+ *
+ * This function destroys an ACL directive structure.
+ *
+ * Arguments:
+ *
+ * acd - pointer to ACL directive structure
+ */
+
+void aclDirectiveDestroy(ACDirective_t * acd)
+{
+ switch (acd->acd_action) {
+ case ACD_ALLOW:
+ case ACD_DENY:
+ {
+ ACClients_t * acp;
+ ACClients_t * nacp;
+
+ /* Free a list of ACClients_t structures */
+ for (acp = acd->acd_cl; acp != 0; acp = nacp) {
+ nacp = acp->cl_next;
+
+ /* Free the HostSpec_t if it's there and unnamed */
+ if ((acp->cl_host != 0) &&
+ (acp->cl_host->hs_sym.sym_name == 0)) {
+ aclHostSpecDestroy(acp->cl_host);
+ }
+
+ /* Free the UserSpec_t if it's there and unnamed */
+ if ((acp->cl_user != 0) &&
+ (acp->cl_user->us_sym.sym_name == 0)) {
+ aclUserSpecDestroy(acp->cl_user);
+ }
+ }
+ }
+ break;
+
+ case ACD_AUTH:
+ {
+ RealmSpec_t * rsp = acd->acd_auth.au_realm;
+
+ /* Destroy the RealmSpec_t if it's unnamed */
+ if ((rsp != 0) && (rsp->rs_sym.sym_name == 0)) {
+ aclRealmSpecDestroy(rsp);
+ }
+ }
+ break;
+ }
+
+ FREE(acd);
+}
+
+/*
+ * Description (aclDNSSpecDestroy)
+ *
+ * This function destroys an entry in a DNS filter. It is intended
+ * mainly to be used by aclHostSpecDestroy().
+ *
+ * Arguments:
+ *
+ * sym - pointer to Symbol_t for DNS filter entry
+ * argp - unused (must be zero)
+ *
+ * Returns:
+ *
+ * The return value is SYMENUMREMOVE.
+ */
+
+int aclDNSSpecDestroy(Symbol_t * sym, void * argp)
+{
+ if (sym != 0) {
+
+ /* Free the DNS specification string if any */
+ if (sym->sym_name != 0) {
+ FREE(sym->sym_name);
+ }
+
+ /* Free the Symbol_t structure */
+ FREE(sym);
+ }
+
+ /* Indicate that the symbol table entry should be removed */
+ return SYMENUMREMOVE;
+}
+
+/*
+ * Description (aclHostSpecDestroy)
+ *
+ * This function destroys a HostSpec_t structure and its sub-structures.
+ *
+ * Arguments:
+ *
+ * hsp - pointer to HostSpec_t structure
+ */
+
+void aclHostSpecDestroy(HostSpec_t * hsp)
+{
+ if (hsp == 0) return;
+
+ /* Free the IP filter if any */
+ if (hsp->hs_host.inh_ipf.ipf_tree != 0) {
+ IPNode_t * ipn; /* current node pointer */
+ IPNode_t * parent; /* parent node pointer */
+ int i;
+
+ /* Traverse tree, freeing nodes */
+ for (parent = hsp->hs_host.inh_ipf.ipf_tree; parent != NULL; ) {
+
+ /* Look for a link to a child node */
+ for (i = 0; i < IPN_NLINKS; ++i) {
+ ipn = parent->ipn_links[i];
+ if (ipn != NULL) break;
+ }
+
+ /* Any children for the parent node? */
+ if (ipn == NULL) {
+
+ /* Otherwise back up the tree */
+ ipn = parent;
+ parent = ipn->ipn_parent;
+
+ /* Free the lower node */
+ FREE(ipn);
+ continue;
+ }
+
+ /*
+ * Found a child node for the current parent.
+ * NULL out the downward link and check it out.
+ */
+ parent->ipn_links[i] = NULL;
+
+ /* Is it a leaf? */
+ if (ipn->ipn_type == IPN_LEAF) {
+ /* Yes, free it */
+ FREE(ipn);
+ continue;
+ }
+
+ /* No, step down the tree */
+ parent = ipn;
+ }
+ }
+
+ /* Free the DNS filter if any */
+ if (hsp->hs_host.inh_dnf.dnf_hash != 0) {
+
+ /* Destroy each entry in the symbol table */
+ symTableEnumerate(hsp->hs_host.inh_dnf.dnf_hash, 0,
+ aclDNSSpecDestroy);
+
+ /* Destroy the symbol table itself */
+ symTableDestroy(hsp->hs_host.inh_dnf.dnf_hash, 0);
+ }
+
+ /* Free the symbol name if any */
+ if (hsp->hs_sym.sym_name != 0) {
+ FREE(hsp->hs_sym.sym_name);
+ }
+
+ /* Free the HostSpec_t structure */
+ FREE(hsp);
+}
+
+/*
+ * Description (aclRealmSpecDestroy)
+ *
+ * This function destroys a RealmSpec_t structure.
+ *
+ * Arguments:
+ *
+ * rsp - pointer to RealmSpec_t structure
+ */
+
+void aclRealmSpecDestroy(RealmSpec_t * rsp)
+{
+ /* Close the realm authentication database if it appears open */
+ if ((rsp->rs_realm.rlm_aif != 0) &&
+ (rsp->rs_realm.rlm_authdb != 0)) {
+ (*rsp->rs_realm.rlm_aif->aif_close)(rsp->rs_realm.rlm_authdb, 0);
+ }
+
+ /* Free the prompt string if any */
+ if (rsp->rs_realm.rlm_prompt != 0) {
+ FREE(rsp->rs_realm.rlm_prompt);
+ }
+
+ /* Free the database filename string if any */
+ if (rsp->rs_realm.rlm_dbname != 0) {
+ FREE(rsp->rs_realm.rlm_dbname);
+ }
+
+ /* Free the realm specification name if any */
+ if (rsp->rs_sym.sym_name != 0) {
+ FREE(rsp->rs_sym.sym_name);
+ }
+
+ /* Free the RealmSpec_t structure */
+ FREE(rsp);
+}
+
+/*
+ * Description (aclRightDef)
+ *
+ * This function find or creates an access right with a specified
+ * name in a given ACL context. If a new access right definition
+ * is created, it assigns a unique integer identifier to the the
+ * right, adds it to the ACL context symbol table and to the
+ * list of all access rights for the context. Note that access
+ * right names are case-insensitive.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acc - pointer to an access control context
+ * rname - access right name (e.g. "GET")
+ * prd - pointer to returned RightDef_t pointer
+ * (may be null)
+ *
+ * Returns:
+ *
+ * The return value is zero if the access right definition already
+ * existed or one if it was created successfully. Otherwise it is
+ * a negative error code (ACLERRxxxx - see aclerror.h), and an error
+ * frame will be generated if an error list is provided.
+ */
+
+int aclRightDef(NSErr_t * errp,
+ ACContext_t * acc, char * rname, RightDef_t **prd)
+{
+ RightDef_t * rdp; /* pointer to right definition */
+ int eid; /* error id code */
+ int rv; /* result value */
+ static int last_rid = 0; /* last assigned right id */
+
+ /* See if there's already a symbol table entry for it */
+ rv = symTableFindSym(acc->acc_stp, rname, ACLSYMRIGHT, (void **)&rdp);
+ if (rv) {
+
+ /* No, create an entry */
+
+ /* Allocate a right definition structure and initialize it */
+ rdp = (RightDef_t *)MALLOC(sizeof(RightDef_t));
+ if (rdp == 0) goto err_nomem;
+
+ rdp->rd_sym.sym_name = STRDUP(rname);
+ rdp->rd_sym.sym_type = ACLSYMRIGHT;
+ rdp->rd_next = acc->acc_rights;
+ rdp->rd_id = ++last_rid;
+
+ /* Add the right name to the symbol table for the ACL context */
+ rv = symTableAddSym(acc->acc_stp, &rdp->rd_sym, (void *)rdp);
+ if (rv) goto err_stadd;
+
+ /* Add the right definition to the list for the ACL context */
+ acc->acc_rights = rdp;
+
+ /* Indicate a new right definition was created */
+ rv = 1;
+ }
+
+ /* Return a pointer to the RightDef_t structure if indicated */
+ if (prd != 0) *prd = rdp;
+
+ return rv;
+
+ err_nomem:
+ eid = ACLERR3600;
+ rv = ACLERRNOMEM;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ goto punt;
+
+ err_stadd:
+ FREE(rdp->rd_sym.sym_name);
+ FREE(rdp);
+ eid = ACLERR3620;
+ rv = ACLERRDUPSYM;
+ nserrGenerate(errp, rv, eid, ACL_Program, 1, rname);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (aclRightSpecDestroy)
+ *
+ * This function destroys a RightSpec_t structure.
+ *
+ * Arguments:
+ *
+ * rsp - pointer to RightSpec_t structure
+ */
+
+void aclRightSpecDestroy(RightSpec_t * rsp)
+{
+ if (rsp != 0) {
+
+ UILFREE(&rsp->rs_list);
+
+ if (rsp->rs_sym.sym_name != 0) {
+ FREE(rsp->rs_sym.sym_name);
+ }
+
+ FREE(rsp);
+ }
+}
+
+/*
+ * Description (aclUserSpecCreate)
+ *
+ * This function allocates and initializes a new UserSpec_t
+ * structure, representing a list of users and groups.
+ *
+ * Arguments:
+ *
+ * None.
+ *
+ * Returns:
+ *
+ * If successful, the return value is a pointer to a new UserSpec_t.
+ * Otherwise the return value is null.
+ */
+
+UserSpec_t * aclUserSpecCreate()
+{
+ UserSpec_t * usp;
+
+ usp = (UserSpec_t *) MALLOC(sizeof(UserSpec_t));
+ if (usp != 0) {
+ memset((void *)usp, 0, sizeof(UserSpec_t));
+ usp->us_sym.sym_type = ACLSYMUSER;
+ }
+
+ return usp;
+}
+
+/*
+ * Description (aclUserSpecDestroy)
+ *
+ * This function destroys a UserSpec_t structure.
+ *
+ * Arguments:
+ *
+ * usp - pointer to UserSpec_t structure
+ */
+
+void aclUserSpecDestroy(UserSpec_t * usp)
+{
+ if (usp != 0) {
+
+ UILFREE(&usp->us_user.uu_user);
+ UILFREE(&usp->us_user.uu_group);
+
+ if (usp->us_sym.sym_name != 0) {
+ FREE(usp->us_sym.sym_name);
+ }
+
+ FREE(usp);
+ }
+}
diff --git a/lib/libaccess/aclcache.cpp b/lib/libaccess/aclcache.cpp
new file mode 100644
index 00000000..34d2ecfb
--- /dev/null
+++ b/lib/libaccess/aclcache.cpp
@@ -0,0 +1,579 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <base/nsassert.h>
+#include <base/crit.h>
+#include <base/ereport.h>
+#include <plhash.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/aclglobal.h>
+#include <libaccess/usrcache.h>
+#include <libaccess/las.h>
+#include <libaccess/ldapacl.h>
+#include "aclutil.h"
+#include "permhash.h"
+#include "aclcache.h"
+
+
+static CRITICAL acl_hash_crit = NULL; /* Controls Global Hash */
+
+enum {
+ ACL_URI_HASH,
+ ACL_URI_GET_HASH
+};
+
+/* ACL_ListHashKeyHash
+ * Given an ACL List address, computes a randomized hash value of the
+ * ACL structure pointer addresses by simply adding them up. Returns
+ * the resultant hash value.
+ */
+static PLHashNumber
+ACL_ListHashKeyHash(const void *Iacllist)
+{
+ PLHashNumber hash=0;
+ ACLWrapper_t *wrap;
+ ACLListHandle_t *acllist=(ACLListHandle_t *)Iacllist;
+
+ for (wrap=acllist->acl_list_head; wrap; wrap=wrap->wrap_next) {
+ hash += (PLHashNumber)(PRSize)wrap->acl;
+ }
+
+ return (hash);
+}
+
+/* ACL_ListHashKeyCompare
+ * Given two acl lists, compares the addresses of the acl pointers within
+ * them to see if theyre identical. Returns 1 if equal, 0 otherwise.
+ */
+static int
+ACL_ListHashKeyCompare(const void *Iacllist1, const void *Iacllist2)
+{
+ ACLWrapper_t *wrap1, *wrap2;
+ ACLListHandle_t *acllist1=(ACLListHandle_t *)Iacllist1;
+ ACLListHandle_t *acllist2=(ACLListHandle_t *)Iacllist2;
+
+ if (acllist1->acl_count != acllist2->acl_count)
+ return 0;
+
+ wrap1 = acllist1->acl_list_head;
+ wrap2 = acllist2->acl_list_head;
+
+ while ((wrap1 != NULL) && (wrap2 != NULL)) {
+ if (wrap1->acl != wrap2->acl)
+ return 0;
+ wrap1 = wrap1->wrap_next;
+ wrap2 = wrap2->wrap_next;
+ }
+
+ if ((wrap1 != NULL) || (wrap2 != NULL))
+ return 0;
+ else
+ return 1;
+}
+
+/* ACL_ListHashValueCompare
+ * Returns 1 if equal, 0 otherwise
+ */
+static int
+ACL_ListHashValueCompare(const void *acllist1, const void *acllist2)
+{
+
+ return (acllist1 == acllist2);
+}
+
+void
+ACL_ListHashInit()
+{
+ ACLListHash = PR_NewHashTable(200,
+ ACL_ListHashKeyHash,
+ ACL_ListHashKeyCompare,
+ ACL_ListHashValueCompare,
+ &ACLPermAllocOps,
+ NULL);
+ if (ACLListHash == NULL) {
+ ereport(LOG_SECURITY, "Unable to allocate ACL List Hash\n");
+ return;
+ }
+
+ return;
+}
+
+static void
+ACL_ListHashDestroy()
+{
+ if (ACLListHash) {
+ PR_HashTableDestroy(ACLListHash);
+ ACLListHash = NULL;
+ }
+
+ return;
+}
+
+/* ACL_ListHashUpdate
+ * Typically called with the &rq->acllist. Checks if the newly generated
+ * acllist matches one that's already been created. If so, toss the new
+ * list and set the pointer to the old list in its place.
+ */
+void
+ACL_ListHashUpdate(ACLListHandle_t **acllistp)
+{
+ NSErr_t *errp = 0;
+ ACLListHandle_t *tmp_acllist;
+
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+
+ tmp_acllist = (ACLListHandle_t *)PR_HashTableLookup(ACLListHash, *acllistp);
+ if (tmp_acllist && tmp_acllist != *acllistp) {
+ NS_ASSERT(*acllistp && *acllistp != ACL_LIST_NO_ACLS);
+ ACL_ListDestroy(errp, *acllistp);
+ *acllistp = tmp_acllist;
+ NS_ASSERT(ACL_CritHeld());
+ tmp_acllist->ref_count++; /* we're gonna use it */
+ } else { /* Wasn't in the list */
+ PR_HashTableAdd(ACLListHash, *acllistp, *acllistp);
+ }
+
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return;
+}
+
+/* ACL_ListCacheEnter
+ * In some cases, the URI cache is useless. E.g. when virtual servers are used.
+ * When that happens, the List Cache is still useful, because the cached ACL
+ * List has the Eval cache in it, plus any LAS caches.
+ */
+NSAPI_PUBLIC void
+ACL_ListHashEnter(ACLListHandle_t **acllistp)
+{
+ NSErr_t *errp = 0;
+
+ ACL_CritEnter();
+
+ /* Look for a matching ACL List and use it if we find one. */
+ if (*acllistp) {
+ NS_ASSERT(*acllistp != ACL_LIST_NO_ACLS);
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ ACL_ListHashUpdate(acllistp);
+ } else {
+ *acllistp = ACL_LIST_NO_ACLS;
+ }
+
+ ACL_CritExit();
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return;
+}
+
+/* ACL_ListHashCheck
+ * When Virtual Servers are active, and the ACL URI cache is inactive, someone
+ * with an old ACL List pointer can check to see if it's still valid. This will
+ * also increment the reference count on it.
+ */
+NSAPI_PUBLIC int
+ACL_ListHashCheck(ACLListHandle_t **acllistp)
+{
+ ACLListHandle_t *tmp_acllist;
+
+ if (*acllistp == ACL_LIST_NO_ACLS) return 1;
+
+ ACL_CritEnter();
+
+ tmp_acllist = (ACLListHandle_t *)PR_HashTableLookup(ACLListHash, *acllistp);
+ if (tmp_acllist) {
+ NS_ASSERT(*acllistp && *acllistp != ACL_LIST_NO_ACLS);
+ *acllistp = tmp_acllist;
+ NS_ASSERT(ACL_CritHeld());
+ tmp_acllist->ref_count++; /* we're gonna use it */
+ ACL_CritExit();
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return 1; /* Normal path */
+ } else { /* Wasn't in the list */
+ ACL_CritExit();
+ return 0;
+ }
+
+}
+
+
+void
+ACL_UriHashDestroy(void)
+{
+ if (acl_uri_hash) {
+ PR_HashTableDestroy(acl_uri_hash);
+ acl_uri_hash = NULL;
+ }
+ if (acl_uri_get_hash) {
+ PR_HashTableDestroy(acl_uri_get_hash);
+ acl_uri_get_hash = NULL;
+ }
+ pool_destroy((void **)acl_uri_hash_pool);
+ acl_uri_hash_pool = NULL;
+
+}
+
+void
+ACL_Destroy(void)
+{
+ ACL_ListHashDestroy();
+ ACL_UriHashDestroy();
+ ACL_LasHashDestroy();
+}
+
+/* Only used in ASSERT statements to verify that we have the lock */
+int
+ACL_CritHeld(void)
+{
+ return (crit_owner_is_me(acl_hash_crit));
+}
+
+NSAPI_PUBLIC void
+ACL_CritEnter(void)
+{
+ crit_enter(acl_hash_crit);
+}
+
+NSAPI_PUBLIC void
+ACL_CritExit(void)
+{
+ crit_exit(acl_hash_crit);
+}
+
+void
+ACL_CritInit(void)
+{
+ acl_hash_crit = crit_init();
+}
+
+void
+ACL_UriHashInit(void)
+{
+ acl_uri_hash = PR_NewHashTable(200,
+ PR_HashString,
+ PR_CompareStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ acl_uri_get_hash = PR_NewHashTable(200,
+ PR_HashString,
+ PR_CompareStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ acl_uri_hash_pool = pool_create();
+}
+
+/* ACL_CacheCheck
+ * INPUT
+ * uri A URI string pointer
+ * acllistp A pointer to an acllist placeholder. E.g. &rq->acllist
+ * OUTPUT
+ * return 1 if cached. 0 if not. The reference count on the ACL List
+ * is INCREMENTED, and will be decremented when ACL_EvalDestroy or
+ * ACL_ListDecrement is
+ * called.
+ */
+int
+ACL_INTCacheCheck(int which, char *uri, ACLListHandle_t **acllistp)
+{
+ PLHashTable *hash;
+ NS_ASSERT(uri && acl_uri_hash && acl_uri_get_hash);
+
+ /* ACL cache: If the ACL List is already in the cache, there's no need
+ * to go through the pathcheck directives.
+ * NULL means that the URI hasn't been accessed before.
+ * ACL_LIST_NO_ACLS
+ * means that the URI has no ACLs.
+ * Anything else is a pointer to the acllist.
+ */
+ ACL_CritEnter();
+
+ /* Get the pointer to the hash table after acquiring the lock */
+ if (which == ACL_URI_HASH)
+ hash = acl_uri_hash;
+ else
+ hash = acl_uri_get_hash;
+
+ *acllistp = (ACLListHandle_t *)PR_HashTableLookup(hash, uri);
+ if (*acllistp != NULL) {
+ if (*acllistp != ACL_LIST_NO_ACLS) {
+ NS_ASSERT((*acllistp)->ref_count >= 0);
+ NS_ASSERT(ACL_CritHeld());
+ (*acllistp)->ref_count++;
+ }
+ ACL_CritExit();
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return 1; /* Normal path */
+ }
+
+ ACL_CritExit();
+ return 0;
+}
+
+int
+ACL_CacheCheckGet(char *uri, ACLListHandle_t **acllistp)
+{
+ return (ACL_INTCacheCheck(ACL_URI_GET_HASH, uri, acllistp));
+}
+
+int
+ACL_CacheCheck(char *uri, ACLListHandle_t **acllistp)
+{
+ return (ACL_INTCacheCheck(ACL_URI_HASH, uri, acllistp));
+}
+
+
+/* ACL_CacheEnter
+ * INPUT
+ * acllist or 0 if there were no ACLs that applied.
+ * OUTPUT
+ * The acllist address may be changed if it matches an existing one.
+ */
+static void
+ACL_INTCacheEnter(int which, char *uri, ACLListHandle_t **acllistp)
+{
+ ACLListHandle_t *tmpacllist;
+ NSErr_t *errp = 0;
+ PLHashTable *hash;
+
+ NS_ASSERT(uri);
+
+ ACL_CritEnter();
+
+ /* Get the pointer to the hash table after acquiring the lock */
+ if (which == ACL_URI_HASH)
+ hash = acl_uri_hash;
+ else
+ hash = acl_uri_get_hash;
+
+ /* Check again (now that we're in the critical section) to see if
+ * someone else created an ACL List for this URI. If so, discard the
+ * list that we made and replace it with the one just found.
+ */
+ tmpacllist = (ACLListHandle_t *)PR_HashTableLookup(hash, uri);
+ if (tmpacllist != NULL) {
+ if (tmpacllist != ACL_LIST_NO_ACLS) {
+ NS_ASSERT(ACL_CritHeld());
+ tmpacllist->ref_count++; /* we're going to use it */
+ }
+ ACL_CritExit();
+ if (*acllistp && *acllistp != ACL_LIST_NO_ACLS) {
+ ACL_ListDestroy(errp, *acllistp);
+ }
+ *acllistp = tmpacllist;
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return;
+ }
+
+ /* Didn't find another list, so put ours in. */
+ /* Look for a matching ACL List and use it if we find one. */
+ if (*acllistp) {
+ NS_ASSERT(*acllistp != ACL_LIST_NO_ACLS);
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ ACL_ListHashUpdate(acllistp);
+ } else {
+ *acllistp = ACL_LIST_NO_ACLS;
+ }
+ PR_HashTableAdd(hash, pool_strdup((void **)acl_uri_hash_pool, uri), (void *)*acllistp);
+
+ ACL_CritExit();
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return;
+}
+
+void
+ACL_CacheEnter(char *uri, ACLListHandle_t **acllistp)
+{
+ ACL_INTCacheEnter(ACL_URI_HASH, uri, acllistp);
+ return;
+}
+
+void
+ACL_CacheEnterGet(char *uri, ACLListHandle_t **acllistp)
+{
+ ACL_INTCacheEnter(ACL_URI_GET_HASH, uri, acllistp);
+ return;
+}
+
+/* ACL_AddAclName
+ * Adds the ACLs for just the terminal object specified in a pathname.
+ * INPUT
+ * path The filesystem pathname of the terminal object.
+ * acllistp The address of the list of ACLs found thus far.
+ * Could be NULL. If so, a new acllist will be allocated (if any
+ * acls are found). Otherwise the existing list will be added to.
+ * masterlist Usually acl_root_30.
+ */
+void
+ACL_AddAclName(char *path, ACLListHandle_t **acllistp, ACLListHandle_t
+*masterlist)
+{
+ ACLHandle_t *acl;
+ NSErr_t *errp = 0;
+
+#ifdef XP_WIN32
+ acl = ACL_ListFind(errp, masterlist, path, ACL_CASE_INSENSITIVE);
+#else
+ acl = ACL_ListFind(errp, masterlist, path, ACL_CASE_SENSITIVE);
+#endif
+ if (!acl)
+ return;
+
+ NS_ASSERT(ACL_AssertAcl(acl));
+
+ if (!*acllistp)
+ *acllistp = ACL_ListNew(errp);
+ ACL_ListAppend(NULL, *acllistp, acl, 0);
+
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return;
+}
+
+
+/* ACL_GetPathAcls
+ * Adds the ACLs for all directories plus the terminal object along a given
+ * filesystem pathname. For each pathname component, look for the name, the
+ * name + "/", and the name + "/*". The last one is because the resource
+ * picker likes to postpend "/*" for directories.
+ * INPUT
+ * path The filesystem pathname of the terminal object.
+ * acllistp The address of the list of ACLs found thus far.
+ * Could be NULL. If so, a new acllist will be allocated (if any
+ * acls are found). Otherwise the existing list will be added to.
+ * prefix A string to be prepended to the path component when looking
+ * for a matching ACL tag.
+ */
+void
+ACL_GetPathAcls(char *path, ACLListHandle_t **acllistp, char *prefix,
+ACLListHandle_t *masterlist)
+{
+ char *slashp=path;
+ int slashidx;
+ char ppath[ACL_PATH_MAX];
+ int prefixlen;
+ char *dst;
+
+ NS_ASSERT(path);
+ NS_ASSERT(prefix);
+
+ dst = strncpy(ppath, prefix, ACL_PATH_MAX);
+ if (dst >= (ppath+ACL_PATH_MAX-1)) {
+ ereport(LOG_SECURITY, "Abort - the path is too long for ACL_GetPathAcls to handle\n");
+ abort();
+ }
+ prefixlen = strlen(ppath);
+
+ /* Handle the first "/". i.e. the root directory */
+ if (*path == '/') {
+ ppath[prefixlen]='/';
+ ppath[prefixlen+1]='\0';
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ strcat(ppath, "*");
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ slashp = path;
+ }
+
+ do {
+ slashp = strchr(++slashp, '/');
+ if (slashp) {
+ slashidx = slashp - path;
+ strncpy(&ppath[prefixlen], path, slashidx);
+ ppath[slashidx+prefixlen] = '\0';
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ /* Must also handle "/a/b/" in addition to "/a/b" */
+ strcat(ppath, "/");
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ strcat(ppath, "*");
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ continue;
+ }
+ strcpy(&ppath[prefixlen], path);
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ strcat(ppath, "/");
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ strcat(ppath, "*");
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ break;
+ } while (slashp);
+
+}
+
+
+static int get_is_owner_default (NSErr_t *errp, PList_t subject,
+ PList_t resource, PList_t auth_info,
+ PList_t global_auth, void *unused)
+{
+ /* Make sure we don't generate error "all getters declined" message from
+ * ACL_GetAttribute.
+ */
+ PListInitProp(subject, ACL_ATTR_IS_OWNER_INDEX, ACL_ATTR_IS_OWNER,
+ "true", 0);
+
+ return LAS_EVAL_TRUE;
+}
+
+
+NSAPI_PUBLIC int
+ACL_Init(void)
+{
+ ACL_InitAttr2Index();
+ ACLGlobal = (ACLGlobal_p)PERM_CALLOC(sizeof(ACLGlobal_s));
+ oldACLGlobal = (ACLGlobal_p)PERM_CALLOC(sizeof(ACLGlobal_s));
+ NS_ASSERT(ACLGlobal && oldACLGlobal);
+ ACL_DATABASE_POOL = pool_create();
+ ACL_METHOD_POOL = pool_create();
+ ACL_CritInit();
+ ACL_UriHashInit();
+ ACL_ListHashInit();
+ ACL_LasHashInit();
+ ACL_Init2();
+ init_ldb_rwlock();
+ ACL_RegisterInit();
+
+ return 0;
+}
+
+/* This one gets called at startup AND at cache flush time. */
+void
+ACL_Init2(void)
+{
+
+ /* Register the ACL functions */
+ ACL_LasRegister(NULL, "timeofday", LASTimeOfDayEval, LASTimeOfDayFlush);
+ ACL_LasRegister(NULL, "dayofweek", LASDayOfWeekEval, LASDayOfWeekFlush);
+ ACL_LasRegister(NULL, "ip", LASIpEval, LASIpFlush);
+ ACL_LasRegister(NULL, "dns", LASDnsEval, LASDnsFlush);
+ ACL_LasRegister(NULL, "dnsalias", LASDnsEval, LASDnsFlush);
+ ACL_LasRegister(NULL, "group", LASGroupEval, (LASFlushFunc_t)NULL);
+ ACL_LasRegister(NULL, "user", LASUserEval, (LASFlushFunc_t)NULL);
+#ifdef MCC_ADMSERV
+ ACL_LasRegister(NULL, "program", LASProgramEval, (LASFlushFunc_t)NULL);
+#endif
+
+ ACL_AttrGetterRegister(NULL, ACL_ATTR_USERDN,
+ get_userdn_ldap,
+ ACL_METHOD_ANY, ACL_DBTYPE_ANY,
+ ACL_AT_END, NULL);
+ return;
+}
+
+NSAPI_PUBLIC int
+ACL_InitPostMagnus(void)
+{
+ int rv;
+
+ rv = ACL_AttrGetterRegister(NULL, ACL_ATTR_IS_OWNER,
+ get_is_owner_default,
+ ACL_METHOD_ANY, ACL_DBTYPE_ANY,
+ ACL_AT_END, NULL);
+ return rv;
+}
+
+NSAPI_PUBLIC int
+ACL_LateInitPostMagnus(void)
+{
+ return acl_usr_cache_init();
+}
diff --git a/lib/libaccess/aclcache.h b/lib/libaccess/aclcache.h
new file mode 100644
index 00000000..1f375bcf
--- /dev/null
+++ b/lib/libaccess/aclcache.h
@@ -0,0 +1,27 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef CACHE_H
+#define CACHE_H
+
+NSPR_BEGIN_EXTERN_C
+
+extern void ACL_ListHashInit(void);
+extern void ACL_ListHashUpdate(ACLListHandle_t **acllistp);
+extern void ACL_Destroy(void);
+extern int ACL_CritHeld(void);
+extern void ACL_CritInit(void);
+extern void ACL_UriHashInit(void);
+extern void ACL_UriHashDestroy(void);
+extern int ACL_CacheCheck(char *uri, ACLListHandle_t **acllist_p);
+extern void ACL_CacheEnter(char *uri, ACLListHandle_t **acllist_p);
+extern void ACL_CacheAbort(ACLListHandle_t **acllist_p);
+extern void ACL_Init2(void);
+extern int ACL_RegisterInit ();
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/aclerror.cpp b/lib/libaccess/aclerror.cpp
new file mode 100644
index 00000000..2cbf2874
--- /dev/null
+++ b/lib/libaccess/aclerror.cpp
@@ -0,0 +1,246 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (aclerror.c)
+ *
+ * This module provides error-handling facilities for ACL-related
+ * errors.
+ */
+
+#include "base/systems.h"
+#ifdef NSPR20
+#include "prprf.h"
+#else
+#include "nspr/prprf.h"
+#endif
+#include <base/nsassert.h>
+#include "libaccess/nserror.h"
+#include "libaccess/nsautherr.h"
+#include "libaccess/aclerror.h"
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+
+#define aclerrnomem XP_GetAdminStr(DBT_AclerrfmtAclerrnomem)
+#define aclerropen XP_GetAdminStr(DBT_AclerrfmtAclerropen)
+#define aclerrdupsym1 XP_GetAdminStr(DBT_AclerrfmtAclerrdupsym1)
+#define aclerrdupsym3 XP_GetAdminStr(DBT_AclerrfmtAclerrdupsym3)
+#define aclerrsyntax XP_GetAdminStr(DBT_AclerrfmtAclerrsyntax)
+#define aclerrundef XP_GetAdminStr(DBT_AclerrfmtAclerrundef)
+#define aclaclundef XP_GetAdminStr(DBT_AclerrfmtAclaclundef)
+#define aclerradb XP_GetAdminStr(DBT_AclerrfmtAclerradb)
+#define aclerrparse1 XP_GetAdminStr(DBT_AclerrfmtAclerrparse1)
+#define aclerrparse2 XP_GetAdminStr(DBT_AclerrfmtAclerrparse2)
+#define aclerrparse3 XP_GetAdminStr(DBT_AclerrfmtAclerrparse3)
+#define aclerrnorlm XP_GetAdminStr(DBT_AclerrfmtAclerrnorlm)
+#define unknownerr XP_GetAdminStr(DBT_AclerrfmtUnknownerr)
+#define aclerrinternal XP_GetAdminStr(DBT_AclerrfmtAclerrinternal)
+#define aclerrinval XP_GetAdminStr(DBT_AclerrfmtAclerrinval)
+#define aclerrfail XP_GetAdminStr(DBT_AclerrfmtAclerrfail)
+#define aclerrio XP_GetAdminStr(DBT_AclerrfmtAclerrio)
+
+/*
+ * Description (aclErrorFmt)
+ *
+ * This function formats an ACL error message into a buffer provided
+ * by the caller. The ACL error information is passed in an error
+ * list structure. The caller can indicate how many error frames
+ * should be processed. A newline is inserted between messages for
+ * different error frames. The error frames on the error list are
+ * all freed, regardless of the maximum depth for traceback.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer
+ * msgbuf - pointer to error message buffer
+ * maxlen - maximum length of generated message
+ * maxdepth - maximum depth for traceback
+ */
+
+void aclErrorFmt(NSErr_t * errp, char * msgbuf, int maxlen, int maxdepth)
+{
+ NSEFrame_t * efp; /* error frame pointer */
+ int len; /* length of error message text */
+ int depth = 0; /* current depth */
+
+ msgbuf[0] = 0;
+
+ while ((efp = errp->err_first) != 0) {
+
+ /* Stop if the message buffer is full */
+ if (maxlen <= 0) break;
+
+ if (depth > 0) {
+ /* Put a newline & tab between error frame messages */
+ *msgbuf++ = '\n';
+ if (--maxlen <= 0) break;
+ *msgbuf++ = '\t';
+ if (--maxlen <= 0) break;
+ }
+
+ if (!strcmp(efp->ef_program, ACL_Program)) {
+
+ /* Identify the facility generating the error and the id number */
+ len = PR_snprintf(msgbuf, maxlen,
+ "[%s%d] ", efp->ef_program, efp->ef_errorid);
+ msgbuf += len;
+ maxlen -= len;
+
+ if (maxlen <= 0) break;
+
+ len = 0;
+
+ switch (efp->ef_retcode) {
+
+ case ACLERRFAIL:
+ case ACLERRNOMEM:
+ case ACLERRINTERNAL:
+ case ACLERRINVAL:
+ switch (efp->ef_errc) {
+ case 3:
+ PR_snprintf(msgbuf, maxlen, efp->ef_errv[0], efp->ef_errv[1], efp->ef_errv[2]);
+ break;
+ case 2:
+ PR_snprintf(msgbuf, maxlen, efp->ef_errv[0], efp->ef_errv[1]);
+ break;
+ case 1:
+ strncpy(msgbuf, efp->ef_errv[0], maxlen);
+ break;
+ default:
+ NS_ASSERT(0); /* don't break -- continue into case 0 */
+ case 0:
+ switch (efp->ef_retcode) {
+ case ACLERRFAIL:
+ strncpy(msgbuf, XP_GetAdminStr(DBT_AclerrfmtAclerrfail), maxlen);
+ break;
+ case ACLERRNOMEM:
+ strncpy(msgbuf, aclerrnomem, maxlen);
+ break;
+ case ACLERRINTERNAL:
+ strncpy(msgbuf, aclerrinternal, maxlen);
+ break;
+ case ACLERRINVAL:
+ strncpy(msgbuf, aclerrinval, maxlen);
+ break;
+ }
+ break;
+ }
+ msgbuf[maxlen-1] = '\0';
+ len = strlen(msgbuf);
+ break;
+
+ case ACLERROPEN:
+ /* File open error: filename, system_errmsg */
+ if (efp->ef_errc == 2) {
+ len = PR_snprintf(msgbuf, maxlen, aclerropen,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ break;
+
+ case ACLERRDUPSYM:
+ /* Duplicate symbol */
+ if (efp->ef_errc == 1) {
+ /* Duplicate symbol: filename, line#, symbol */
+ len = PR_snprintf(msgbuf, maxlen, aclerrdupsym1,
+ efp->ef_errv[0]);
+ }
+ else if (efp->ef_errc == 3) {
+ /* Duplicate symbol: symbol */
+ len = PR_snprintf(msgbuf, maxlen, aclerrdupsym3,
+ efp->ef_errv[0], efp->ef_errv[1],
+ efp->ef_errv[2]);
+ }
+ break;
+
+ case ACLERRSYNTAX:
+ if (efp->ef_errc == 2) {
+ /* Syntax error: filename, line# */
+ len = PR_snprintf(msgbuf, maxlen, aclerrsyntax,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ break;
+
+ case ACLERRUNDEF:
+ if (efp->ef_errorid == ACLERR3800) {
+ /* Undefined symbol: acl, method/database name */
+ len = PR_snprintf(msgbuf, maxlen, aclaclundef,
+ efp->ef_errv[0], efp->ef_errv[1],
+ efp->ef_errv[2]);
+ }
+ else if (efp->ef_errc == 3) {
+ /* Undefined symbol: filename, line#, symbol */
+ len = PR_snprintf(msgbuf, maxlen, aclerrundef,
+ efp->ef_errv[0], efp->ef_errv[1],
+ efp->ef_errv[2]);
+ }
+ break;
+
+ case ACLERRADB:
+ if (efp->ef_errc == 2) {
+ /* Authentication database error: DB name, symbol */
+ len = PR_snprintf(msgbuf, maxlen, aclerradb,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ break;
+
+ case ACLERRPARSE:
+ if (efp->ef_errc == 2) {
+ /* Parse error: filename, line# */
+ len = PR_snprintf(msgbuf, maxlen, aclerrparse2,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ else if (efp->ef_errc == 3) {
+ /* Parse error: filename, line#, token */
+ len = PR_snprintf(msgbuf, maxlen, aclerrparse3,
+ efp->ef_errv[0], efp->ef_errv[1],
+ efp->ef_errv[2]);
+ }
+ else if (efp->ef_errc == 1) {
+ /* Parse error: line or pointer */
+ len = PR_snprintf(msgbuf, maxlen, aclerrparse1,
+ efp->ef_errv[0]);
+ }
+ break;
+
+ case ACLERRNORLM:
+ if (efp->ef_errc == 1) {
+ /* No realm: name */
+ len = PR_snprintf(msgbuf, maxlen, aclerrnorlm,
+ efp->ef_errv[0]);
+ }
+ break;
+
+ case ACLERRIO:
+ if (efp->ef_errc == 2) {
+ len = PR_snprintf(msgbuf, maxlen, aclerrio,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ break;
+
+ default:
+ len = PR_snprintf(msgbuf, maxlen, unknownerr, efp->ef_retcode);
+ break;
+ }
+ }
+ else if (!strcmp(efp->ef_program, NSAuth_Program)) {
+ nsadbErrorFmt(errp, msgbuf, maxlen, maxdepth - depth);
+ }
+ else {
+ len = PR_snprintf(msgbuf, maxlen, unknownerr, efp->ef_retcode);
+ }
+
+ msgbuf += len;
+ maxlen -= len;
+
+ /* Free this frame */
+ nserrFFree(errp, efp);
+
+ if (++depth >= maxdepth) break;
+ }
+
+ /* Free any remaining error frames */
+ nserrDispose(errp);
+}
diff --git a/lib/libaccess/acleval.cpp b/lib/libaccess/acleval.cpp
new file mode 100644
index 00000000..a2be1f7b
--- /dev/null
+++ b/lib/libaccess/acleval.cpp
@@ -0,0 +1,556 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (acleval.c)
+ *
+ * This module provides functions for evaluating Access Control List
+ * (ACL) structures in memory.
+ *
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "libaccess/symbols.h"
+#include "libaccess/aclerror.h"
+#include "libaccess/acleval.h"
+#include <assert.h>
+
+/*
+ * Description (RLMEQUIV)
+ *
+ * Macro for realm comparison. Both realm pointers must be non-null.
+ * The realms are equivalent if the pointers are equal, or if the
+ * authentication methods and database names are the same. The
+ * prompt string is not considered.
+ */
+#define RLMEQUIV(rlm1, rlm2) (((rlm1) != 0) && ((rlm2) != 0) && \
+ (((rlm1) == (rlm2)) || \
+ (((rlm1)->rlm_ameth == (rlm2)->rlm_ameth) && \
+ ((rlm1)->rlm_dbname != 0) && \
+ ((rlm2)->rlm_dbname != 0) && \
+ !strcmp((rlm1)->rlm_dbname, \
+ (rlm2)->rlm_dbname))))
+
+int aclDNSLookup(DNSFilter_t * dnf, char * dnsspec, int fqdn, char **match)
+{
+ char * subdns; /* suffix of client DNS name */
+ void * table; /* hash table pointer */
+ Symbol_t * sym; /* DNS spec symbol pointer */
+ int rv; /* result value */
+
+ fqdn = (fqdn) ? 1 : 0;
+
+ if (match) *match = 0;
+
+ /* Handle null or empty filter */
+ if ((dnf == 0) || (dnf->dnf_hash == 0)) {
+
+ return ACL_NOMATCH;
+ }
+
+ /* Got the client's DNS name? */
+ if (!dnsspec || !*dnsspec) {
+ /* No, use special one */
+ dnsspec = "unknown";
+ }
+
+ /* Get hash table pointer */
+ table = dnf->dnf_hash;
+
+ /*
+ * Look up each possible suffix for the client domain name,
+ * starting with the entire string, and working toward the
+ * last component.
+ */
+
+ subdns = dnsspec;
+
+ while (subdns != 0) {
+
+ /* Look up the domain name suffix in the hash table */
+ rv = symTableFindSym(table, subdns, fqdn, (void **)&sym);
+ if (rv == 0) break;
+
+ /* Step to the next level */
+ if (subdns[0] == '.') subdns += 1;
+ subdns = strchr(subdns, '.');
+
+ /* If it was fully qualified, now it's not */
+ fqdn = 0;
+ }
+
+ /* One more possibility if nothing found yet... */
+ if (rv) {
+ rv = symTableFindSym(table, "*", 0, (void **)&sym);
+ }
+
+ if (rv == 0) {
+ if (match) *match = sym->sym_name;
+ rv = ACL_DNMATCH;
+ }
+ else rv = ACL_NOMATCH;
+
+ return rv;
+}
+
+int aclIPLookup(IPFilter_t * ipf, IPAddr_t ipaddr, void **match)
+{
+ IPLeaf_t * leaf; /* radix tree leaf pointer */
+ IPAddr_t bitmask; /* bit mask for current node */
+ IPNode_t * ipn; /* current internal node */
+ IPNode_t * lastipn; /* last internal node seen in search */
+ IPNode_t * mipn; /* ipn_masked subtree root pointer */
+
+ if (match) *match = 0;
+
+ /* Handle null or empty IP filter */
+ if ((ipf == 0) || (ipf->ipf_tree == 0)) goto fail;
+
+ lastipn = NULL;
+ ipn = ipf->ipf_tree;
+
+ /*
+ * The tree traversal first works down the tree, under the assumption
+ * that all of the bits in the given IP address may be significant.
+ * The internal nodes of the tree will cause particular bits of the
+ * IP address to be tested, and the ipn_clear or ipn_set link to
+ * a descendant followed accordingly. The internal nodes are arranged
+ * in such a way that high-order bits are tested before low-order bits.
+ * Usually some bits are skipped, as they are not needed to distinguish
+ * the entries in the tree.
+ *
+ * At the bottom of the tree, a leaf node may be found, or the last
+ * descendant link may be NULL. If a leaf node is found, it is
+ * tested for a match against the given IP address. If it doesn't
+ * match, or the link was NULL, backtracking begins, as described
+ * below.
+ *
+ * Backtracking follows the ipn_parent links back up the tree from
+ * the last internal node, looking for internal nodes with ipn_masked
+ * descendants. The subtrees attached to these links are traversed
+ * downward, as before, with the same processing at the bottom as
+ * the first downward traversal. Following the ipn_masked links is
+ * essentially examining the possibility that the IP address bit
+ * associated with the internal node may be masked out by the
+ * ipl_netmask in a leaf at the bottom of such a subtree. Since
+ * the ipn_masked links are examined from the bottom of the tree
+ * to the top, this looks at the low-order bits first.
+ */
+
+ while (ipn != NULL) {
+
+ /*
+ * Work down the tree testing bits in the IP address indicated
+ * by the internal nodes. Exit the loop when there are no more
+ * internal nodes.
+ */
+ while ((ipn != NULL) && (ipn->ipn_type == IPN_NODE)) {
+
+ /* Save pointer to internal node */
+ lastipn = ipn;
+
+ /* Get a mask for the bit this node tests */
+ bitmask = (IPAddr_t) 1<<ipn->ipn_bit;
+
+ /* Select link to follow for this IP address */
+ ipn = (bitmask & ipaddr) ? ipn->ipn_set : ipn->ipn_clear;
+ }
+
+ /* Did we end up with a non-NULL node pointer? */
+ if (ipn != NULL) {
+
+ /* It must be a leaf node */
+ assert(ipn->ipn_type == IPN_LEAF);
+ leaf = (IPLeaf_t *)ipn;
+
+ /* Is it a matching leaf? */
+ if (leaf->ipl_ipaddr == (ipaddr & leaf->ipl_netmask)) goto win;
+ }
+
+ /*
+ * Backtrack, starting at lastipn. Search each subtree
+ * emanating from an ipn_masked link. Step up the tree
+ * until the ipn_masked link of the node referenced by
+ * "ipf->ipf_tree" has been considered.
+ */
+
+ for (ipn = lastipn; ipn != NULL; ipn = ipn->ipn_parent) {
+
+ /*
+ * Look for a node with a non-NULL masked link, but don't
+ * go back to the node we just came from.
+ */
+
+ if ((ipn->ipn_masked != NULL) && (ipn->ipn_masked != lastipn)) {
+
+ /* Get the root of this subtree */
+ mipn = ipn->ipn_masked;
+
+ /* If this is an internal node, start downward traversal */
+ if (mipn->ipn_type == IPN_NODE) {
+ ipn = mipn;
+ break;
+ }
+
+ /* Otherwise it's a leaf */
+ assert(mipn->ipn_type == IPN_LEAF);
+ leaf = (IPLeaf_t *)mipn;
+
+ /* Is it a matching leaf? */
+ if (leaf->ipl_ipaddr == (ipaddr & leaf->ipl_netmask)) goto win;
+ }
+
+ /* Don't consider nodes above the given root */
+ if (ipn == ipf->ipf_tree) goto fail;
+
+ lastipn = ipn;
+ }
+ }
+
+ fail:
+ /* No matching entry found */
+ return ACL_NOMATCH;
+
+ win:
+ /* Found a match in leaf */
+ if (match) *match = (void *)leaf;
+
+ return ACL_IPMATCH;
+}
+
+int aclUserLookup(UidUser_t * uup, UserObj_t * uoptr)
+{
+ int gl1cnt; /* elements left in uup->uu_group list */
+ int gl2cnt; /* elements left in uoptr->uo_groups list */
+ USI_t * gl1ptr; /* pointer to next group in uup->uu_group */
+ USI_t * gl2ptr; /* pointer to next group in uoptr->uo_groups */
+
+ /* Try for a direct match on the user id */
+ if (usiPresent(&uup->uu_user, uoptr->uo_uid)) {
+ return ACL_USMATCH;
+ }
+
+ /*
+ * Now we want to see if there are any matches between the
+ * uup->uu_group group id list and the list of groups in the
+ * user object.
+ */
+
+ gl1cnt = UILCOUNT(&uup->uu_group);
+ gl1ptr = UILLIST(&uup->uu_group);
+ gl2cnt = UILCOUNT(&uoptr->uo_groups);
+ gl2ptr = UILLIST(&uoptr->uo_groups);
+
+ while ((gl1cnt > 0) && (gl2cnt > 0)) {
+
+ if (*gl1ptr == *gl2ptr) {
+ return ACL_GRMATCH;
+ }
+
+ if (*gl1ptr < *gl2ptr) {
+ ++gl1ptr;
+ --gl1cnt;
+ }
+ else {
+ ++gl2ptr;
+ --gl2cnt;
+ }
+ }
+
+ return ACL_NOMATCH;
+}
+
+/*
+ * Description (aclEvaluate)
+ *
+ * This function evaluates a given ACL against specified client
+ * information and a particular access right that is needed to
+ * service the client. It can optionally return the ACL directive
+ * number which allows or denies the client's access.
+ *
+ * Arguments:
+ *
+ * acl - pointer to ACL to evaluate
+ * arid - desired access right id value
+ * clauth - pointer to client authentication information
+ * padn - pointer to returned ACL directive number
+ * (may be null)
+ *
+ * Returns:
+ *
+ * A return value of zero indicates that the given ACL does not
+ * control the desired access right, or contains no directives which
+ * match the specified client. A positive return value contains a
+ * value of ACD_ALLOW, ACD_DENY, or ACD_AUTH, and may also have the
+ * ACD_ALWAYS bit flag set. The value indicates whether the client
+ * should be allowed or denied access, or whether authentication is
+ * needed. The ACD_ALWAYS flag indicates if the action should occur
+ * immediately, terminating any further ACL evaluation. An error
+ * is indicated by a negative error code (ACLERRxxxx - see aclerror.h).
+ */
+
+int aclEvaluate(ACL_t * acl, USI_t arid, ClAuth_t * clauth, int * padn)
+{
+ ACDirective_t * acd; /* current ACL directive pointer */
+ RightSpec_t * rsp; /* pointer to rights controlled by ACL */
+ ACClients_t * csp; /* pointer to clients specification */
+ HostSpec_t * hsp; /* pointer to host specification */
+ UserSpec_t * usp; /* pointer to user specification */
+ Realm_t * rlm = 0; /* current authentication realm pointer */
+ Realm_t * authrlm = 0; /* realm to be used for authentication */
+ int ndir; /* ACL directive number */
+ int rv; /* result value */
+ int decision = 0; /* current access control decision */
+ int result = 0; /* function return value */
+ int mdn = 0; /* matching directive number */
+
+ if (padn) *padn = 0;
+
+ /* Does this ACL control the desired access right? */
+
+ rsp = acl->acl_rights;
+ if ((rsp == 0) || !usiPresent(&rsp->rs_list, arid)) {
+
+ /* No, nothing to do */
+ return 0;
+ }
+
+ ndir = 0;
+
+ /* Loop on each ACL directive */
+ for (acd = acl->acl_dirf; acd != 0; acd = acd->acd_next) {
+
+ /* Bump directive number */
+ ++ndir;
+
+ /* Dispatch on directive action code */
+ switch (acd->acd_action) {
+
+ case ACD_ALLOW:
+ case ACD_DENY:
+
+ /* Loop to process list of client specifications */
+ for (csp = acd->acd_cl; csp != 0; csp = csp->cl_next) {
+
+ /* Is there a host list? */
+ hsp = csp->cl_host;
+ if (hsp != 0) {
+
+ /* An empty host list will not match */
+ rv = 0;
+
+ /* Yes, is there an IP address filter? */
+ if (hsp->hs_host.inh_ipf.ipf_tree != 0) {
+
+ /*
+ * Yes, see if the the client's IP address
+ * matches anything in the IP filter.
+ */
+ rv = aclIPLookup(&hsp->hs_host.inh_ipf,
+ clauth->cla_ipaddr, 0);
+ }
+
+ /* If no IP match, is there a DNS filter? */
+ if (!rv && (hsp->hs_host.inh_dnf.dnf_hash != 0)) {
+
+ /* Yes, try for a DNS match */
+ rv = aclDNSLookup(&hsp->hs_host.inh_dnf,
+ clauth->cla_dns, 1, 0);
+ }
+
+ /*
+ * Does the client match the host list? If not, skip
+ * to the next client specification.
+ */
+ if (!rv) continue;
+ }
+
+ /* Is there a user list? */
+ usp = csp->cl_user;
+ if (usp != 0) {
+
+ /* Yes, has the client user been authenticated yet? */
+ if ((clauth->cla_realm != 0) && (clauth->cla_uoptr != 0)) {
+
+ /*
+ * Yes, has the client user been authenticated in the
+ * realm associated with this user list?
+ */
+ if (RLMEQUIV(rlm, clauth->cla_realm)) {
+
+ /*
+ * Yes, does the user spec allow all
+ * authenticated users?
+ */
+ rv = (usp->us_flags & ACL_USALL) ? ACL_GRMATCH : 0;
+ if (!rv) {
+
+ /*
+ * No, need to check client user against list.
+ */
+ rv = aclUserLookup(&usp->us_user,
+ clauth->cla_uoptr);
+ }
+
+ /* Got a match yet? */
+ if (rv) {
+
+ /*
+ * Yes, update the the access control decision,
+ * clearing any pending authentication request
+ * flag.
+ */
+ authrlm = 0;
+ decision = acd->acd_action;
+
+ /* Copy the "always" flag to the result */
+ result = (acd->acd_flags & ACD_ALWAYS);
+ mdn = ndir;
+ }
+ }
+ else {
+
+ /*
+ * The client has been authenticated already,
+ * but not in the realm used by this directive.
+ * Since directives in a given ACL are not
+ * independent policy statements, it seems that
+ * the proper thing to do here is to reject
+ * this ACL in its entirity. This case is not
+ * an authentication failure per se, but rather
+ * an inability to evaluate this particular
+ * ACL directive which requires authentication.
+ */
+ return 0;
+ }
+ }
+ else {
+
+ /*
+ * The client user has not been authenticated in this
+ * realm yet, but could potentially be one of the
+ * users on this user list. This directive is
+ * therefore "potentially matching". The question
+ * is: would it change the current decision to allow
+ * or deny the client if the client user actually did
+ * match the user list?
+ */
+ if ((authrlm == 0) && (decision != acd->acd_action)) {
+
+ /*
+ * Yes, set the "request authentication" flag,
+ * along with ACD_ALWAYS if it is set in the
+ * directive.
+ */
+ authrlm = rlm;
+ decision = ACD_AUTH;
+ result = (acd->acd_flags & ACD_ALWAYS);
+ mdn = ndir;
+ }
+ }
+ }
+ else {
+
+ /*
+ * There is no user list. Therefore any user,
+ * authenticated or not, is considered a match.
+ * Update the decision, and clear the
+ * "authentication requested" flag.
+ */
+ authrlm = 0;
+ decision = acd->acd_action;
+ result = (acd->acd_flags & ACD_ALWAYS);
+ mdn = ndir;
+ }
+
+ /*
+ * If we hit a client specification that requires
+ * immediate action, exit the loop.
+ */
+ if (result & ACD_ALWAYS) break;
+ }
+ break;
+
+ case ACD_AUTH:
+
+ /* Got a pointer to a realm specification? */
+ if (acd->acd_auth.au_realm != 0) {
+
+ /* Yes, update the current realm pointer */
+ rlm = &acd->acd_auth.au_realm->rs_realm;
+
+ /* Has the client already successfully authenticated? */
+ if ((clauth->cla_realm == 0) || (clauth->cla_uoptr == 0)) {
+
+ /*
+ * No, if this is an "always" directive, override any
+ * previously selected realm and request authentication.
+ */
+ if ((acd->acd_flags & ACD_ALWAYS) != 0) {
+
+ /* Set decision to request authentication */
+ authrlm = rlm;
+ decision = ACD_AUTH;
+ result = ACD_ALWAYS;
+ mdn = ndir;
+ }
+ }
+ }
+ break;
+
+ case ACD_EXEC:
+
+ /* Conditionally terminate ACL evaluation */
+ switch (decision) {
+ case ACD_ALLOW:
+ if (acd->acd_flags & ACD_EXALLOW) {
+ result = (acd->acd_flags & ACD_ALWAYS);
+ goto out;
+ }
+ break;
+ case ACD_DENY:
+ if (acd->acd_flags & ACD_EXDENY) {
+ result = (acd->acd_flags & ACD_ALWAYS);
+ goto out;
+ }
+ break;
+ case ACD_AUTH:
+ if (acd->acd_flags & ACD_EXAUTH) {
+ result = (acd->acd_flags & ACD_ALWAYS);
+ goto out;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * If we hit a directive that requires immediate action, exit
+ * the loop.
+ */
+ if (result & ACD_ALWAYS) break;
+ }
+
+ out:
+ /* If the decision is to request authentication, set the desired realm */
+ if (decision == ACD_AUTH) {
+ clauth->cla_realm = authrlm;
+ }
+
+ /* Combine decision with flags already in result */
+ result |= decision;
+
+ /* Return matching directive number if desired */
+ if (padn) *padn = mdn;
+
+ return result;
+}
diff --git a/lib/libaccess/aclflush.cpp b/lib/libaccess/aclflush.cpp
new file mode 100644
index 00000000..dfee47d6
--- /dev/null
+++ b/lib/libaccess/aclflush.cpp
@@ -0,0 +1,178 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Source file for the ACL_CacheFlush-related routines.
+ */
+
+#include <base/nsassert.h>
+#include <base/util.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/aclglobal.h>
+#include <libaccess/las.h>
+#include "aclcache.h"
+#include <libaccess/dbtlibaccess.h>
+
+extern void ACL_DatabaseDestroy(void);
+
+PRIntn
+deletelists(PRHashEntry *he, PRIntn i, void *arg)
+{
+ ACLListHandle_t *acllist=(ACLListHandle_t *)he->value;
+ NSErr_t *errp = 0;
+
+ NS_ASSERT(he);
+ NS_ASSERT(he->value);
+
+ if (acllist->ref_count) {
+ // If the list is in use, increment the counter. Then set the
+ // stale flag. The other user can't delete the list since we're
+ // counted as well. Finally, decrement the counter and whoever
+ // sets it to zero will delete the ACL List.
+ NS_ASSERT(ACL_CritHeld());
+ acllist->ref_count++;
+ acllist->flags |= ACL_LIST_STALE;
+ if (--acllist->ref_count == 0)
+ ACL_ListDestroy(errp, acllist);
+ } else {
+ ACL_ListDestroy(errp, acllist);
+ }
+
+ return 0;
+}
+
+PRIntn
+restartdeletelists(PRHashEntry *he, PRIntn i, void *arg)
+{
+ NSErr_t *errp = 0;
+
+ // Cannot be anyone left using the lists, so just free them no matter
+ // what.
+ ACLListHandle_t *acllist=(ACLListHandle_t *)he->value;
+
+ NS_ASSERT(he);
+ NS_ASSERT(he->value);
+
+ ACL_ListDestroy(errp, acllist);
+
+ return 0;
+}
+
+static AclCacheFlushFunc_t AclCacheFlushRoutine = NULL;
+
+NSAPI_PUBLIC int
+ACL_CacheFlushRegister(AclCacheFlushFunc_t flush_func)
+{
+ NS_ASSERT(flush_func);
+ AclCacheFlushRoutine = flush_func;
+
+ return 0;
+}
+
+NSAPI_PUBLIC int
+ACL_CacheFlush(void)
+{
+ ACLGlobal_p newACLGlobal;
+ NSErr_t *errp = 0;
+
+ NS_ASSERT(ACLGlobal);
+ NS_ASSERT(ACLGlobal->masterlist);
+ NS_ASSERT(ACLGlobal->listhash);
+ NS_ASSERT(ACLGlobal->urihash);
+ NS_ASSERT(ACLGlobal->urigethash);
+ NS_ASSERT(ACLGlobal->pool);
+
+ ACL_CritEnter();
+
+ // Swap the pointers. Keep using the current database/method tables
+ // until the new ones are built. This is a kludge. An in-progress
+ // evaluation could conceivably get messed up, but the window seems
+ // small.
+ newACLGlobal = oldACLGlobal;
+
+ oldACLGlobal = ACLGlobal;
+ ACLGlobal = newACLGlobal;
+
+ // Prepare the new ACLGlobal structure
+ ACL_UriHashInit(); /* Also initializes ACLGlobal->pool */
+ ACL_ListHashInit();
+ ACLGlobal->evalhash = oldACLGlobal->evalhash;
+ ACLGlobal->flushhash = oldACLGlobal->flushhash;
+ ACLGlobal->methodhash = oldACLGlobal->methodhash;
+ ACLGlobal->dbtypehash = oldACLGlobal->dbtypehash;
+ ACLGlobal->dbnamehash = oldACLGlobal->dbnamehash;
+ ACLGlobal->attrgetterhash = oldACLGlobal->attrgetterhash;
+ ACLGlobal->databasepool = oldACLGlobal->databasepool;
+ ACLGlobal->methodpool = oldACLGlobal->methodpool;
+
+ // Mark all existing ACL Lists as stale. Delete any unreferenced ones.
+ PR_HashTableEnumerateEntries(oldACLGlobal->listhash, deletelists, NULL);
+
+ // Delete the old master list.
+ ACL_ListDestroy(errp, oldACLGlobal->masterlist);
+ oldACLGlobal->masterlist = NULL;
+ PR_HashTableDestroy(oldACLGlobal->listhash);
+ oldACLGlobal->listhash = NULL;
+ PR_HashTableDestroy(oldACLGlobal->urihash);
+ oldACLGlobal->urihash = NULL;
+ PR_HashTableDestroy(oldACLGlobal->urigethash);
+ oldACLGlobal->urigethash = NULL;
+ pool_destroy(oldACLGlobal->pool);
+ oldACLGlobal->pool = NULL;
+ memset(oldACLGlobal, 0, sizeof(ACLGlobal_s));
+
+
+ // Read in the ACLs again in lib/frame
+ if (AclCacheFlushRoutine) {
+ (*AclCacheFlushRoutine)();
+ }
+
+ ACL_CritExit();
+
+ return 0;
+}
+
+
+NSAPI_PUBLIC void
+ACL_Restart(void *clntData)
+{
+ NSErr_t *errp = 0;
+
+ NS_ASSERT(ACLGlobal);
+ NS_ASSERT(ACLGlobal->masterlist);
+ NS_ASSERT(ACLGlobal->listhash);
+ NS_ASSERT(ACLGlobal->urihash);
+ NS_ASSERT(ACLGlobal->urigethash);
+ NS_ASSERT(ACLGlobal->pool);
+
+ // Unlike ACL_CacheFlush, this routine can be much more cavalier about
+ // freeing up memory, since there's guaranteed to be no users about at
+ // this time.
+
+ ACL_DatabaseDestroy();
+ ACL_MethodSetDefault(errp, ACL_METHOD_INVALID);
+
+ // Mark all existing ACL Lists as stale. Delete any unreferenced ones
+ // (i.e. all of them)
+ PR_HashTableEnumerateEntries(ACLGlobal->listhash, restartdeletelists, NULL);
+
+ // Delete the master list.
+ ACL_ListDestroy(errp, ACLGlobal->masterlist);
+
+ ACL_LasHashDestroy();
+ PR_HashTableDestroy(ACLGlobal->listhash);
+ PR_HashTableDestroy(ACLGlobal->urihash);
+ PR_HashTableDestroy(ACLGlobal->urigethash);
+ pool_destroy(ACLGlobal->pool);
+
+ PERM_FREE(ACLGlobal);
+ ACLGlobal = NULL;
+ PERM_FREE(oldACLGlobal);
+ oldACLGlobal = NULL;
+
+ return;
+}
diff --git a/lib/libaccess/aclparse.cpp b/lib/libaccess/aclparse.cpp
new file mode 100644
index 00000000..d8c429fe
--- /dev/null
+++ b/lib/libaccess/aclparse.cpp
@@ -0,0 +1,2241 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (aclparse.c)
+ *
+ * This module provides functions for parsing a file containing
+ * Access Control List (ACL) definitions. It builds a representation
+ * of the ACLs in memory, using the services of the aclbuild module.
+ */
+
+#include <base/systems.h>
+#include <base/file.h>
+#include <base/util.h>
+#include <netsite.h>
+#include <libaccess/nsadb.h>
+#include <libaccess/aclerror.h>
+#include <libaccess/aclparse.h>
+#include <libaccess/symbols.h>
+
+#ifdef XP_UNIX
+#include <sys/types.h>
+#include <netinet/in.h> /* ntohl */
+#include <arpa/inet.h>
+#endif
+
+void * aclChTab = 0; /* character class table handle */
+
+static char * classv[] = {
+ " \t\r\f\013", /* class 0 - whitespace */
+ "\n", /* class 1 - newline */
+ ",.;@*()+{}\"\'", /* class 2 - special characters */
+ "0123456789", /* class 3 - digits */
+ /* class 4 - letters */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+ "-", /* class 5 - hyphen */
+ "_", /* class 6 - underscore */
+ "/-_.:" /* class 7 - filename special characters */
+};
+
+static int classc = sizeof(classv)/sizeof(char *);
+
+/*
+ * Description (aclAuthListParse)
+ *
+ * This function parses an auth-list. An auth-list specifies
+ * combinations of user/group names and host addresses/names.
+ * An auth-list entry can identify a collection of users and/or
+ * groups, a collection of hosts by IP addresses or DNS names,
+ * or a combination of the two. Each auth-spec adds another
+ * ACClients_t structure to the specified list.
+ *
+ * The syntax for an auth-list is:
+ *
+ * auth-list ::= auth-spec | auth-list "," auth-spec
+ * auth-spec ::= auth-users [at-token auth-hosts]
+ * auth-users - see aclAuthUsersParse()
+ * auth-hosts - see aclAuthHostsParse()
+ * at-token ::= "at" | "@"
+ *
+ * The caller provides a pointer to a ClientSpec_t structure,
+ * which is built up with new information as auth-specs are parsed.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * acc - pointer to ACL context object
+ * rlm - pointer to authentication realm object
+ * clsp - pointer to returned ACClients_t list head
+ *
+ * Returns:
+ *
+ * If successful, the return value is the token type of the token
+ * following the auth-list, i.e. the first token which is not
+ * recognized as the start of an auth-spec. It is the caller's
+ * responsibility to validate this token as a legitimate terminator
+ * of an auth-list. If a parsing error occurs in the middle of
+ * an auth-spec, the return value is ACLERRPARSE, and an error frame
+ * is generated if an error list is provided. For other kinds of
+ * errors a negative error code (from aclerror.h) is returned.
+ */
+
+int aclAuthListParse(NSErr_t * errp, ACLFile_t * acf,
+ ACContext_t * acc, Realm_t * rlm, ACClients_t **clsp)
+{
+ void * token = acf->acf_token; /* token handle */
+ ACClients_t * csp; /* client spec pointer */
+ UserSpec_t * usp; /* user spec pointer */
+ HostSpec_t * hsp; /* host spec pointer */
+ int rv; /* result value */
+ int eid; /* error id */
+
+ /* Loop once for each auth-spec */
+ for (rv = acf->acf_ttype; ; rv = aclGetToken(errp, acf, 0)) {
+
+ usp = 0;
+ hsp = 0;
+
+ /* Parse auth-users into user and group lists in the ACClients_t */
+ rv = aclAuthUsersParse(errp, acf, rlm, &usp, 0);
+ if (rv < 0) break;
+
+ /* Is the at-token there? */
+ if ((rv == TOKEN_AT) || !strcasecmp(lex_token(token), KEYWORD_AT)) {
+
+ /* Step to the next token after the at-token */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) break;
+
+ /* Parse auth-hosts part, adding information to the HostSpec_t */
+ rv = aclAuthHostsParse(errp, acf, acc, &hsp);
+ if (rv < 0) break;
+ }
+
+ /* Create a new ACClients_t structure for the parsed information */
+ csp = (ACClients_t *)MALLOC(sizeof(ACClients_t));
+ if (csp == 0) goto err_nomem;
+
+ csp->cl_next = 0;
+ csp->cl_user = usp;
+ csp->cl_host = hsp;
+
+ /* Add it to the end of the list referenced by clsp */
+ while (*clsp != 0) clsp = &(*clsp)->cl_next;
+ *clsp = csp;
+
+ /* Need a "," to keep going */
+ if (rv != TOKEN_COMMA) break;
+ }
+
+ return rv;
+
+ err_nomem:
+ eid = ACLERR1000;
+ nserrGenerate(errp, ACLERRNOMEM, eid, ACL_Program, 0);
+ return ACLERRNOMEM;
+}
+
+/*
+ * Description (aclAuthHostsParse)
+ *
+ * This function parses a list of IP address and/or DNS name
+ * specifications, adding information to the IP and DNS filters
+ * associated with a specified HostSpec_t. The syntax of the
+ * auth-hosts construct is:
+ *
+ * auth-hosts ::= auth-host-elem | "(" auth-host-list ")"
+ * | "hosts" host-list-name
+ * auth-host-elem ::= auth-ip-spec | auth-dns-spec
+ * auth-ip-spec ::= ipaddr | ipaddr netmask
+ * auth-dns-spec ::= fqdn | dns-suffix
+ * auth-host-list ::= auth-host-elem | auth-host-list "," auth-host-elem
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * acc - pointer to ACL context object
+ * hspp - pointer to HostSpec_t pointer
+ *
+ * Returns:
+ *
+ * If successful, the return value is the token type of the token
+ * following the auth-hosts, i.e. either the first token after a
+ * single auth-host-elem or the first token after the closing ")"
+ * of a list of auth-host-elems. It is the caller's responsibility
+ * to validate this token as a legitimate successor of auth-hosts.
+ * If a parsing error occurs in the middle of auth-hosts, the return
+ * value is ACLERRPARSE, and an error frame is generated if an error
+ * list is provided. For other kinds of errors a negative error
+ * code (from aclerror.h) is returned.
+ */
+
+int aclAuthHostsParse(NSErr_t * errp,
+ ACLFile_t * acf, ACContext_t * acc, HostSpec_t **hspp)
+{
+ void * token = acf->acf_token; /* token handle */
+ char * tokenstr; /* token string pointer */
+ int islist = 0; /* true if auth-host-list */
+ int fqdn; /* fully qualified domain name */
+ IPAddr_t ipaddr; /* IP address value */
+ IPAddr_t netmask; /* IP netmask value */
+ int arv; /* alternate result value */
+ int rv; /* result value */
+ int eid; /* error id */
+ char linestr[16]; /* line number string buffer */
+
+ rv = acf->acf_ttype;
+
+ /* Are we starting an auth-host-list? */
+ if (rv == TOKEN_LPAREN) {
+
+ /* Yes, it appears so */
+ islist = 1;
+
+ /* Step token to first auth-host-elem */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+ }
+ else if (rv == TOKEN_IDENT) {
+
+ /* Could this be "hosts host-list-name"? */
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_HOSTS)) {
+
+ /* We don't support lists of host lists yet */
+ if (*hspp != 0) goto err_unshl;
+
+ /* Get host-list-name */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+
+ if (rv != TOKEN_IDENT) goto err_hlname;
+
+ tokenstr = lex_token(token);
+
+ /* Look up the host-list-name in the ACL symbol table */
+ rv = symTableFindSym(acc->acc_stp,
+ tokenstr, ACLSYMHOST, (void **)hspp);
+ if (rv < 0) goto err_undefhl;
+
+ /* Step to token after the host-list-name */
+ rv = aclGetToken(errp, acf, 0);
+
+ return rv;
+ }
+ }
+
+ /* Loop for each auth-host-elem */
+ for (rv = acf->acf_ttype; ; rv = aclGetToken(errp, acf, 0)) {
+
+ /* Does this look like an auth-ip-spec? */
+ if (rv == TOKEN_NUMBER) {
+
+ /* Yes, go parse it */
+ rv = aclGetIPAddr(errp, acf, &ipaddr, &netmask);
+ if (rv < 0) goto punt;
+
+ arv = aclAuthIPAdd(hspp, ipaddr, netmask);
+ if (arv < 0) goto err_ipadd;
+ }
+ else if ((rv == TOKEN_STAR) || (rv == TOKEN_IDENT)) {
+
+ /* Get fully qualified DNS name indicator value */
+ fqdn = (rv == TOKEN_IDENT) ? 1 : 0;
+
+ /* This looks like the start of an auth-dns-spec */
+ rv = aclGetDNSString(errp, acf);
+ if (rv < 0) goto punt;
+
+ tokenstr = lex_token(token);
+
+ /* If the DNS spec begins with "*.", strip the "*" */
+ if (tokenstr && (tokenstr[0] == '*') && (tokenstr[1] == '.')) {
+ tokenstr += 1;
+ }
+
+ arv = aclAuthDNSAdd(hspp, tokenstr, fqdn);
+ if (arv < 0) goto err_dnsadd;
+
+ /* Pick up the next token */
+ rv = aclGetToken(errp, acf, 0);
+ }
+ else break;
+
+ /* If this is a list, we need a "," to keep going */
+ if (!islist || (rv != TOKEN_COMMA)) break;
+ }
+
+ /* Were we parsing an auth-host-list? */
+ if (islist) {
+
+ /* Yes, check for closing ")" */
+ if (acf->acf_ttype != TOKEN_RPAREN) goto err_norp;
+
+ /* Got it. Step to next token for caller. */
+ rv = aclGetToken(errp, acf, 0);
+ }
+
+ punt:
+ return rv;
+
+ err_unshl:
+ eid = ACLERR1100;
+ goto err_parse;
+
+ err_hlname:
+ eid = ACLERR1120;
+ goto err_parse;
+
+ err_undefhl:
+ eid = ACLERR1140;
+ rv = ACLERRUNDEF;
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 3, acf->acf_filename, linestr, tokenstr);
+ goto punt;
+
+ err_ipadd:
+ eid = ACLERR1180;
+ rv = arv;
+ goto err_ret;
+
+ err_dnsadd:
+ eid = ACLERR1200;
+ rv = arv;
+ goto err_ret;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ goto punt;
+
+ err_norp:
+ eid = ACLERR1220;
+ err_parse:
+ rv = ACLERRPARSE;
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+ goto punt;
+}
+
+/*
+ * Description (aclAuthUsersParse)
+ *
+ * This function parses a list of users and groups subject to
+ * authorization, adding the information to a specified UserSpec_t.
+ * The syntax it parses is:
+ *
+ * auth-users ::= auth-user-elem | "(" auth-user-list ")"
+ * auth-user-elem ::= username | groupname
+ * | "all" | "anyone"
+ * auth-user-list ::= auth-user-elem | auth-user-list "," auth-user-elem
+ *
+ * If the 'elist' argument is non-null, an auth-user-list will be
+ * accepted without the enclosing parentheses. Any invalid user
+ * or group names will not cause a fatal error, but will be returned
+ * in an array of strings via 'elist'.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * rlm - pointer to authentication realm object
+ * uspp - pointer to UserSpec_t pointer
+ * elist - pointer to returned pointer to array
+ * of strings containing invalid user or
+ * group names (may be null)
+ *
+ * Returns:
+ *
+ * If successful, the return value is the token type of the token
+ * following the auth-users, i.e. either the first token after a
+ * single auth-user-elem or the first token after the closing ")"
+ * of a list of auth-user-elems. It is the caller's responsibility
+ * to validate this token as a legitimate successor of auth-users.
+ * If a parsing error occurs in the middle of auth-users, the return
+ * value is ACLERRPARSE, and an error frame is generated if an error
+ * list is provided. For other kinds of errors a negative error
+ * code (from aclerror.h) is returned.
+ */
+
+int aclAuthUsersParse(NSErr_t * errp, ACLFile_t * acf,
+ Realm_t * rlm, UserSpec_t **uspp, char ***elist)
+{
+ void * token = acf->acf_token; /* token handle */
+ char * tokenstr; /* token string pointer */
+ UserSpec_t * usp; /* user list head structure */
+ int islist = 0; /* true if auth-user-list */
+ int inlist = 0; /* true if UserSpec_t was supplied */
+ int any = 0; /* true if KEYWORD_ANY seen */
+ int all = 0; /* true if KEYWORD_ALL seen */
+ int elemcnt = 0; /* count of auth-user-elem seen */
+ int elen = 0; /* length of evec in (char *) */
+ int ecnt = 0; /* entries used in evec */
+ char **evec = 0; /* list of bad user/group names */
+ int rv; /* result value */
+ int eid; /* error id */
+ char linestr[16]; /* line number string buffer */
+ int errc = 2;
+
+ usp = *uspp;
+ if ((usp != 0) && (usp->us_flags & ACL_USALL)) all = 1;
+
+ if (elist != 0) inlist = 1;
+ else {
+
+ /* Check for opening "(" */
+ if (acf->acf_ttype == TOKEN_LPAREN) {
+
+ /* Looks like an auth-user-list */
+ islist = 1;
+
+ /* Step token to first auth-user-elem */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+ }
+ }
+
+ /* Loop for each auth-user-elem */
+ for (rv = acf->acf_ttype; ; rv = aclGetToken(errp, acf, 0)) {
+
+ /* Looking for a user or group identifier */
+ if ((rv == TOKEN_IDENT) || (rv == TOKEN_STRING)) {
+
+ /*
+ * If KEYWORD_ALL or KEYWORD_ANY has already appeared
+ * in this auth-spec, then return an error.
+ */
+ if (all | any) goto err_allany;
+
+ /* Check for reserved words */
+ tokenstr = lex_token(token);
+
+ /* KEYWORD_AT begins auth-hosts, but is invalid here */
+ if (!strcasecmp(tokenstr, KEYWORD_AT)) break;
+
+ /* Check for special group names */
+ if (!strcasecmp(tokenstr, KEYWORD_ANY)) {
+
+ /*
+ * Any user, with no authentication needed. This can
+ * only appear once in an auth-spec, and cannot be used
+ * in combination with KEYWORD_ALL (or any other user or
+ * group identifiers, but that will get checked before
+ * we return).
+ */
+
+ if ((elemcnt > 0) || (usp != 0)) goto err_any;
+ any = 1;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_ALL)) {
+
+ /*
+ * Any authenticated user. This can only appear once in
+ * an auth-spec, and cannot be used in combination with
+ * KEYWORD_ANY (or any other user or group identifiers,
+ * but that will get checked before we return).
+ */
+
+ if (elemcnt > 0) goto err_all;
+
+ /* Create a UserSpec_t structure if we haven't got one yet */
+ if (usp == 0) {
+ usp = aclUserSpecCreate();
+ if (usp == 0) goto err_nomem1;
+ *uspp = usp;
+ }
+
+ usp->us_flags |= ACL_USALL;
+ all = 1;
+ }
+ else {
+
+ /* Create a UserSpec_t structure if we haven't got one yet */
+ if (usp == 0) {
+ usp = aclUserSpecCreate();
+ if (usp == 0) goto err_nomem2;
+ *uspp = usp;
+ }
+
+ /* This should be a user or group name */
+ rv = aclAuthNameAdd(errp, usp, rlm, tokenstr);
+ if (rv <= 0) {
+
+ /* The name was not found in the authentication DB */
+ if (elist != 0) {
+ if (evec == 0) {
+ evec = (char **)MALLOC(4*sizeof(char *));
+ evec[0] = 0;
+ ecnt = 1;
+ elen = 4;
+ }
+ else if (ecnt >= elen) {
+ elen += 4;
+ evec = (char **)REALLOC(evec, elen*sizeof(char *));
+ }
+ evec[ecnt-1] = STRDUP(tokenstr);
+ evec[ecnt] = 0;
+ ++ecnt;
+
+ }
+ else if (rv < 0) goto err_badgun;
+ }
+
+ /* Don't allow duplicate names */
+ if (rv & ANA_DUP) {
+ if (elist == 0) goto err_dupgun;
+ }
+ }
+
+ /* Count number of auth-user-elems seen */
+ elemcnt += 1;
+
+ /* Get the token after the auth-user-elem */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+ }
+
+ /* If this is a list, we need a "," to keep going */
+ if (!(islist | inlist) || (rv != TOKEN_COMMA)) break;
+ }
+
+ /* Were we parsing an auth-user-list? */
+ if (islist) {
+
+ /* Yes, check for closing ")" */
+ if (acf->acf_ttype != TOKEN_RPAREN) goto err_norp;
+
+ /* Got it. Step to next token for caller. */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+ }
+
+ /*
+ * If we didn't see any auth-user-elems, then the auth-user we were
+ * called to parse is missing. We will forgive and forget if the
+ * current token is a comma, however, so as to allow empty auth-specs.
+ */
+ if ((elemcnt <= 0) && (rv != TOKEN_COMMA)) {
+ goto err_noelem;
+ }
+
+ punt:
+ /* Return list of bad names if indicated */
+ if (elist != 0) *elist = evec;
+
+ return rv;
+
+ err_badgun:
+ /* Encountered an unknown user or group name */
+ eid = ACLERR1360;
+ rv = ACLERRUNDEF;
+ goto err_retgun;
+
+ err_dupgun:
+ /* A user or group name was specified multiple times */
+ eid = ACLERR1380;
+ rv = ACLERRDUPSYM;
+ goto err_retgun;
+
+ err_retgun:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 3, acf->acf_filename, linestr, tokenstr);
+ goto punt;
+
+ err_norp:
+ /* Missing ")" */
+ eid = ACLERR1400;
+ goto err_parse;
+
+ err_noelem:
+ eid = ACLERR1420;
+ goto err_parse;
+
+ err_all:
+ eid = ACLERR1440;
+ goto err_parse;
+
+ err_any:
+ eid = ACLERR1460;
+ goto err_parse;
+
+ err_allany:
+ eid = ACLERR1480;
+ goto err_parse;
+
+ err_nomem1:
+ eid = ACLERR1500;
+ rv = ACLERRNOMEM;
+ errc = 0;
+ goto err_ret;
+
+ err_nomem2:
+ eid = ACLERR1520;
+ rv = ACLERRNOMEM;
+ errc = 0;
+ goto err_ret;
+
+ err_parse:
+ rv = ACLERRPARSE;
+ err_ret:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, errc, acf->acf_filename, linestr);
+ goto punt;
+}
+
+/*
+ * Description (aclDirectivesParse)
+ *
+ * This function parses the directives inside an ACL definition.
+ * The syntax for a directive list is:
+ *
+ * dir-list ::= directive | dir-list ";" directive
+ * directive ::= auth-directive | access-directive | exec-directive
+ * auth-directive ::= dir-force "authenticate" ["in" realm-spec]
+ * access-directive ::= dir-force dir-access auth-list
+ * exec-directive ::= dir-force "execute" ["if" exec-optlist]
+ * exec-optlist ::= exec-condition | exec-optlist "," exec-condition
+ * exec-condition ::= dir-access | "authenticate"
+ * dir-force ::= "Always" | "Default"
+ * dir-access ::= "allow" | "deny"
+ *
+ * See aclAuthListParse() for auth-list syntax.
+ * See aclRealmSpecParse() for realm-spec syntax.
+ *
+ * The caller provides a pointer to an ACL structure, which is
+ * built up with new information as directives are parsed.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * acl - pointer to ACL structure
+ *
+ * Returns:
+ *
+ * If successful, the return value is the token type of the token
+ * following the directive list, i.e. the first token which is not
+ * recognized as the start of a directive. It is the caller's
+ * responsibility to validate this token as a legitimate terminator
+ * of a directive list. If a parsing error occurs in the middle of
+ * a directive, the return value is ACLERRPARSE, and an error frame
+ * is generated if an error list is provided. For other kinds of
+ * errors a negative error code (from aclerror.h) is returned.
+ */
+
+int aclDirectivesParse(NSErr_t * errp, ACLFile_t * acf, ACL_t * acl)
+{
+ void * token = acf->acf_token; /* token handle */
+ char * tokenstr; /* token string */
+ Realm_t * rlm = 0; /* current realm pointer */
+ ACDirective_t * acd; /* directive pointer */
+ int action; /* directive action code */
+ int flags; /* directive action flags */
+ int arv; /* alternate return value */
+ int rv; /* result value */
+ int eid; /* error id */
+ char linestr[16]; /* line number string buffer */
+
+ /* Look for top-level directives */
+ for (rv = acf->acf_ttype; ; rv = aclGetToken(errp, acf, 0)) {
+
+ action = 0;
+ flags = 0;
+
+ /* Check for beginning of directive */
+ if (rv == TOKEN_IDENT) {
+
+ /* Check identifier for directive dir-force keywords */
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_DEFAULT)) {
+ flags = ACD_DEFAULT;
+ }
+ else if (!strcasecmp(tokenstr, "always")) {
+ flags = ACD_ALWAYS;
+ }
+ else break;
+
+ /*
+ * Now we're looking for dir-access, "authenticate",
+ * or "execute".
+ */
+ rv = aclGetToken(errp, acf, 0);
+
+ /* An identifier would be nice ... */
+ if (rv != TOKEN_IDENT) goto err_access;
+
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_AUTH)) {
+
+ /* process auth-directive */
+ action = ACD_AUTH;
+
+ /* Create a new directive object */
+ acd = aclDirectiveCreate();
+ if (acd == 0) goto err_nomem1;
+
+ /* Get the next token after KEYWORD_AUTH */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) break;
+
+ /* Could we have "in" realm-spec here? */
+ if (rv == TOKEN_IDENT) {
+
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_IN)) {
+
+ /* Get the next token after KEYWORD_IN */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) break;
+
+ /* Parse the realm-spec */
+ rv = aclRealmSpecParse(errp, acf, acl->acl_acc,
+ &acd->acd_auth.au_realm);
+ if (rv < 0) break;
+
+ /* Set current realm */
+ if (acd->acd_auth.au_realm != 0) {
+
+ /* Close database in current realm if any */
+ if (rlm && rlm->rlm_authdb) {
+ (*rlm->rlm_aif->aif_close)(rlm->rlm_authdb, 0);
+ rlm->rlm_authdb = 0;
+ }
+
+ rlm = &acd->acd_auth.au_realm->rs_realm;
+ }
+ }
+ }
+
+ /* Add this directive to the ACL */
+ acd->acd_action = action;
+ acd->acd_flags = flags;
+
+ arv = aclDirectiveAdd(acl, acd);
+ if (arv < 0) goto err_diradd1;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_EXECUTE)) {
+
+ /* process exec-directive */
+ action = ACD_EXEC;
+
+ /* Create a new directive object */
+ acd = aclDirectiveCreate();
+ if (acd == 0) goto err_nomem3;
+
+ /* Get the next token after KEYWORD_EXECUTE */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) break;
+
+ /* Could we have "if" exec-optlist here? */
+ if (rv == TOKEN_IDENT) {
+
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_IF)) {
+
+ for (;;) {
+
+ /* Get the next token after KEYWORD_IF or "," */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) break;
+
+ /*
+ * Looking for "allow", "deny", or "authenticate"
+ */
+ if (rv == TOKEN_IDENT) {
+
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_ALLOW)) {
+ flags |= ACD_EXALLOW;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_DENY)) {
+ flags |= ACD_EXDENY;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_AUTH)) {
+ flags |= ACD_EXAUTH;
+ }
+ else goto err_exarg;
+ }
+
+ /* End of directive if no comma */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) break;
+
+ if (rv != TOKEN_COMMA) break;
+ }
+ }
+ }
+ else flags = (ACD_EXALLOW|ACD_EXDENY|ACD_EXAUTH);
+
+ if (rv < 0) break;
+
+ /* Add this directive to the ACL */
+ acd->acd_action = action;
+ acd->acd_flags = flags;
+
+ arv = aclDirectiveAdd(acl, acd);
+ if (arv < 0) goto err_diradd3;
+ }
+ else {
+
+ /* process access-directive */
+
+ if (!strcasecmp(tokenstr, KEYWORD_ALLOW)) {
+ action = ACD_ALLOW;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_DENY)) {
+ action = ACD_DENY;
+ }
+ else goto err_acctype;
+
+ /* Get the next token after dir-access */
+ rv = aclGetToken(errp, acf, 0);
+
+ /* Create a new directive object */
+ acd = aclDirectiveCreate();
+ if (acd == 0) goto err_nomem2;
+
+ /* Parse a list of auth-specs */
+ rv = aclAuthListParse(errp, acf, acl->acl_acc, rlm,
+ &acd->acd_cl);
+ if (rv < 0) break;
+
+ /* Add this directive to the ACL */
+ acd->acd_action = action;
+ acd->acd_flags = flags;
+
+ arv = aclDirectiveAdd(acl, acd);
+ if (arv < 0) goto err_diradd2;
+ }
+ }
+
+ /* Need a ";" to keep going */
+ if (rv != TOKEN_EOS) break;
+ }
+
+ punt:
+ /* Close database in current realm if any */
+ if (rlm && rlm->rlm_authdb) {
+ (*rlm->rlm_aif->aif_close)(rlm->rlm_authdb, 0);
+ rlm->rlm_authdb = 0;
+ }
+
+ return rv;
+
+ err_access:
+ /* dir-access not present */
+ eid = ACLERR1600;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_acctype:
+ /* dir-access identifier is invalid */
+ eid = ACLERR1620;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_diradd1:
+ eid = ACLERR1640;
+ rv = arv;
+ tokenstr = 0;
+ goto err_ret;
+
+ err_diradd2:
+ eid = ACLERR1650;
+ rv = arv;
+ tokenstr = 0;
+ goto err_ret;
+
+ err_nomem1:
+ eid = ACLERR1660;
+ rv = ACLERRNOMEM;
+ tokenstr = 0;
+ goto err_ret;
+
+ err_nomem2:
+ eid = ACLERR1680;
+ rv = ACLERRNOMEM;
+ tokenstr = 0;
+ goto err_ret;
+
+ err_nomem3:
+ eid = ACLERR1685;
+ rv = ACLERRNOMEM;
+ tokenstr = 0;
+ goto err_ret;
+
+ err_diradd3:
+ eid = ACLERR1690;
+ rv = arv;
+ tokenstr = 0;
+ goto err_ret;
+
+ err_exarg:
+ eid = ACLERR1695;
+ rv = ACLERRSYNTAX;
+ goto err_ret;
+
+ err_ret:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ if (tokenstr) {
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 3, acf->acf_filename, linestr, tokenstr);
+ }
+ else {
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 2, acf->acf_filename, linestr);
+ }
+ goto punt;
+}
+
+/*
+ * Description (aclACLParse)
+ *
+ * This function parses a data stream containing ACL definitions,
+ * and builds a representation of the ACLs in memory. Each ACL
+ * has a user-specified name, and a pointer to the ACL structure
+ * is stored under the name in a symbol table provided by the caller.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * acc - pointer to ACContext_t structure
+ * flags - bit flags (unused - must be zero)
+ *
+ * Returns:
+ *
+ * The return value is zero if the stream is parsed successfully.
+ * Otherwise it is a negative error code (ACLERRxxxx - see aclerror.h),
+ * and an error frame will be generated if an error list is provided.
+ */
+
+int aclACLParse(NSErr_t * errp, ACLFile_t * acf, ACContext_t * acc, int flags)
+{
+ void * token = acf->acf_token; /* handle for current token */
+ char * tokenstr; /* current token string */
+ char * aclname; /* ACL name string */
+ ACL_t * aclp; /* pointer to ACL structure */
+ int rv; /* result value */
+ int eid; /* error id value */
+ char linestr[16]; /* line number string buffer */
+
+ /* Look for top-level statements */
+ for (;;) {
+
+ /* Get a token to begin a statement */
+ rv = aclGetToken(errp, acf, 0);
+
+ /* An identifier would be nice ... */
+ if (rv != TOKEN_IDENT) {
+
+ /* Empty statements are ok, if pointless */
+ if (rv == TOKEN_EOS) continue;
+
+ /* EOF is valid here */
+ if (rv == TOKEN_EOF) break;
+
+ /* Anything else is unacceptable */
+ goto err_nostmt;
+ }
+
+ /* Check identifier for statement keywords */
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_ACL)) {
+
+ /* ACL name rights-list { acl-def-list }; */
+
+ /* Get the name of the ACL */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv != TOKEN_IDENT) goto err_aclname;
+ aclname = lex_token(token);
+
+ /* Create the ACL structure */
+ rv = aclCreate(errp, acc, aclname, &aclp);
+ if (rv < 0) goto punt;
+
+ /* Get the next token after the ACL name */
+ rv = aclGetToken(errp, acf, 0);
+
+ /* Parse the rights specification */
+ rv = aclRightsParse(errp, acf, acc, &aclp->acl_rights);
+
+ /* Want a "{" to open the ACL directive list */
+ if (rv != TOKEN_LBRACE) {
+ if (rv < 0) goto punt;
+ goto err_aclopen;
+ }
+
+ /* Get the first token in the ACL directive list */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+
+ /* Parse the ACL directive list */
+ rv = aclDirectivesParse(errp, acf, aclp);
+
+ /* Want a "}" to close the ACL directive list */
+ if (rv != TOKEN_RBRACE) {
+ if (rv < 0) goto punt;
+ goto err_aclclose;
+ }
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_INCLUDE)) {
+ /* Include "filename"; */
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_REALM)) {
+ /* Realm name realm-spec */
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_RIGHTS)) {
+ /* Rights name rights-def; */
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_HOSTS)) {
+ /* Hosts name auth-hosts; */
+ }
+ else goto err_syntax;
+ }
+
+ return 0;
+
+ err_nostmt:
+ eid = ACLERR1700;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_aclname:
+ eid = ACLERR1720;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_aclopen:
+ eid = ACLERR1740;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_aclclose:
+ eid = ACLERR1760;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_ret:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+ goto punt;
+
+ err_syntax:
+ eid = ACLERR1780;
+ rv = ACLERRPARSE;
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 3, acf->acf_filename, linestr, tokenstr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (aclFileClose)
+ *
+ * This function closes an ACL file previously opened by aclFileOpen(),
+ * and frees any associated data structures.
+ *
+ * Arguments:
+ *
+ * acf - pointer to ACL file information
+ * flags - bit flags (unused - must be zero)
+ */
+
+void aclFileClose(ACLFile_t * acf, int flags)
+{
+ if (acf != 0) {
+
+ /* Destroy the associated lexer stream if any */
+ if (acf->acf_lst != 0) {
+ lex_stream_destroy(acf->acf_lst);
+ }
+
+ /* Close the file if it's open */
+ if (acf->acf_fd != SYS_ERROR_FD) {
+ system_fclose(acf->acf_fd);
+ }
+
+ /* Destroy any associated token */
+ if (acf->acf_token != 0) {
+ lex_token_destroy(acf->acf_token);
+ }
+
+ /* Free the filename string if any */
+ if (acf->acf_filename != 0) {
+ FREE(acf->acf_filename);
+ }
+
+ /* Free the ACLFile_t structure */
+ FREE(acf);
+ }
+}
+
+/*
+ * Description (aclFileOpen)
+ *
+ * This function opens a specified filename and creates a structure
+ * to contain information about the file during parsing. This
+ * includes a handle for a LEX data stream for the file.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * filename - name of file to be opened
+ * flags - bit flags (unused - must be zero)
+ * pacf - pointer to returned ACLFile_t pointer
+ *
+ * Returns:
+ *
+ * The return value is zero if the file is opened successfully, and
+ * a pointer to the ACLFile_t is returned in the location specified
+ * by 'pacf'. Otherwise a negative error code (ACLERRxxxx - see
+ * aclerror.h) is returned, and an error frame will be generated if
+ * an error list is provided.
+ */
+
+int aclFileOpen(NSErr_t * errp,
+ char * filename, int flags, ACLFile_t **pacf)
+{
+ ACLFile_t * acf; /* pointer to ACL file structure */
+ int rv; /* return value */
+ int eid; /* error identifier */
+ char * errmsg; /* system error message string */
+
+ *pacf = 0;
+
+ /* Allocate the ACLFile_t structure */
+ acf = (ACLFile_t *)MALLOC(sizeof(ACLFile_t));
+ if (acf == 0) goto err_nomem1;
+
+ memset((void *)acf, 0, sizeof(ACLFile_t));
+ acf->acf_filename = STRDUP(filename);
+ acf->acf_lineno = 1;
+ acf->acf_flags = flags;
+
+ /* Create a LEX token object */
+ rv = lex_token_new((pool_handle_t *)0, 32, 8, &acf->acf_token);
+ if (rv < 0) goto err_nomem2;
+
+ /* Open the file */
+ acf->acf_fd = system_fopenRO(acf->acf_filename);
+ if (acf->acf_fd == SYS_ERROR_FD) goto err_open;
+
+ /* Create a LEX stream for the file */
+ acf->acf_lst = lex_stream_create(aclStreamGet,
+ (void *)acf->acf_fd, 0, 8192);
+ if (acf->acf_lst == 0) goto err_nomem3;
+
+ *pacf = acf;
+ return 0;
+
+ err_open: /* file open error */
+ rv = ACLERROPEN;
+ eid = ACLERR1900;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
+ goto punt;
+
+ err_nomem1: /* MALLOC of ACLFile_t failed */
+ rv = ACLERRNOMEM;
+ eid = ACLERR1920;
+ goto err_mem;
+
+ err_nomem2: /* lex_token_new() failed */
+ rv = ACLERRNOMEM;
+ eid = ACLERR1940;
+ goto err_mem;
+
+ err_nomem3: /* lex_stream_create() failed */
+ system_fclose(acf->acf_fd);
+ rv = ACLERRNOMEM;
+ eid = ACLERR1960;
+
+ err_mem:
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ goto punt;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (aclGetDNSString)
+ *
+ * This function parses a DNS name specification, which consists
+ * of a sequence of DNS name components separated by ".". Each
+ * name component must start with a letter, and contains only
+ * letters, digits, and hyphens. An exception is that the first
+ * component may be the wildcard indicator, "*". This function
+ * assumes that the current token already contains a TOKEN_STAR
+ * or TOKEN_IDENT. The complete DNS name specification is
+ * returned as the current token string.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ *
+ * Returns:
+ *
+ * The character terminating the DNS name specification is returned
+ * as the function value. The current token type is unchanged, but
+ * the string associated with the current token contains the
+ * complete DNS name specification. An error is indicated by a
+ * negative return value, and an error frame is generated if an
+ * error list is provided.
+ */
+
+int aclGetDNSString(NSErr_t * errp, ACLFile_t * acf)
+{
+ LEXStream_t * lst = acf->acf_lst; /* LEX stream handle */
+ void * token = acf->acf_token; /* LEX token handle */
+ int rv; /* result value */
+ int eid; /* error id value */
+ char linestr[16]; /* line number string buffer */
+
+ /* The current token should be TOKEN_STAR or TOKEN_IDENT */
+ rv = acf->acf_ttype;
+
+ if ((rv != TOKEN_STAR) && (rv != TOKEN_IDENT)) goto err_dns1;
+
+ /* Loop to parse [ "." dns-component ]+ */
+ for (;;) {
+
+ /* Try to step over a "." */
+ rv = lex_next_char(lst, aclChTab, 0);
+
+ /* End of DNS string if there's not one there */
+ if (rv != '.') break;
+
+ /* Append the "." to the token string */
+ (void)lex_token_append(token, 1, ".");
+
+ /* Advance the input stream past the "." */
+ rv = lex_next_char(lst, aclChTab, CCM_SPECIAL);
+
+ /* Next we want to see a letter */
+ rv = lex_next_char(lst, aclChTab, 0);
+
+ /* Error if it's not there */
+ if (!lex_class_check(aclChTab, rv, CCM_LETTER)) goto err_dns2;
+
+ /* Append a string of letters, digits, hyphens to token */
+ rv = lex_scan_over(lst, aclChTab, (CCM_LETTER|CCM_DIGIT|CCM_HYPHEN),
+ token);
+ if (rv < 0) goto err_dns3;
+ }
+
+ punt:
+ return rv;
+
+ err_dns1:
+ eid = ACLERR2100;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_dns2:
+ eid = ACLERR2120;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_dns3:
+ eid = ACLERR2140;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_ret:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+ goto punt;
+}
+
+int aclGetFileSpec(NSErr_t * errp, ACLFile_t * acf, int flags)
+{
+ LEXStream_t * lst = acf->acf_lst; /* LEX stream handle */
+ void * token = acf->acf_token; /* LEX token handle */
+ char * tokenstr; /* token string pointer */
+ int rv; /* result value */
+ int eid; /* error id value */
+ char linestr[16]; /* line number string buffer */
+
+ /* Skip whitespace */
+ rv = lex_skip_over(lst, aclChTab, CCM_WS);
+ if (rv < 0) goto err_lex1;
+
+ /* Begin a new token string */
+ rv = lex_token_start(token);
+
+ rv = lex_scan_over(lst, aclChTab, CCM_FILENAME, token);
+ if (rv < 0) goto err_lex2;
+
+ tokenstr = lex_token(token);
+
+ if (!tokenstr || !*tokenstr) goto err_nofn;
+
+ punt:
+ return rv;
+
+ err_lex1:
+ eid = ACLERR2900;
+ goto err_parse;
+
+ err_lex2:
+ eid = ACLERR2920;
+ goto err_parse;
+
+ err_nofn:
+ eid = ACLERR2940;
+
+ err_parse:
+ rv = ACLERRPARSE;
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+ goto punt;
+}
+
+/*
+ * Description (aclGetIPAddr)
+ *
+ * This function retrieves an IP address specification from a given
+ * input stream. The specification consists of an IP address expressed
+ * in the standard "." notation, possibly followed by whitespace and a
+ * netmask, also in "." form. The IP address and netmask values are
+ * returned. If no netmask is specified, a default value of 0xffffffff
+ * is returned.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * pip - pointer to returned IP address value
+ * pmask - pointer to returned IP netmask value
+ *
+ * Returns:
+ *
+ * If successful, the return value identifies the type of the token
+ * following the IP address specification. This token type value is
+ * also returned in acf_ttype. An error is indicated by a negative
+ * error code (ACLERRxxxx - see aclerror.h), and an error frame will
+ * be generated if an error list is provided. The token type code in
+ * acf_ttype is TOKEN_ERROR when an error code is returned.
+ */
+
+int aclGetIPAddr(NSErr_t * errp,
+ ACLFile_t * acf, IPAddr_t * pip, IPAddr_t * pmask)
+{
+ LEXStream_t * lst = acf->acf_lst; /* LEX stream handle */
+ void * token = acf->acf_token; /* LEX token handle */
+ char * tokenstr; /* token string pointer */
+ IPAddr_t ipaddr; /* IP address */
+ IPAddr_t netmask; /* IP netmask */
+ int dotcnt; /* count of '.' seen in address */
+ int rv; /* result value */
+ int eid; /* error id value */
+ char linestr[16]; /* line number string buffer */
+
+ /* Set default return values */
+ *pip = 0;
+ *pmask = 0xffffffff;
+
+ rv = acf->acf_ttype;
+
+ /* The current token must be a number */
+ if (rv != TOKEN_NUMBER) {
+
+ /* No IP address present */
+ return rv;
+ }
+
+ /* Assume no netmask */
+ netmask = 0xffffffff;
+
+ for (dotcnt = 0;;) {
+
+ /* Append digits and letters to the current token */
+ rv = lex_scan_over(lst, aclChTab, (CCM_DIGIT|CCM_LETTER), token);
+ if (rv < 0) goto err_lex1;
+
+ /* Stop when no "." follows the digits and letters */
+ if (rv != '.') break;
+
+ /* Stop if we've already seen three "." */
+ if (++dotcnt > 3) break;
+
+ /* Advance past the "." */
+ (void)lex_next_char(lst, aclChTab, CCM_SPECIAL);
+
+ /* Check the next character for a "*" */
+ rv = lex_next_char(lst, aclChTab, 0);
+ if (rv == '*') {
+
+ /* Advance past the "*" */
+ (void)lex_next_char(lst, aclChTab, CCM_SPECIAL);
+
+ netmask <<= ((4-dotcnt)*8);
+ netmask = htonl(netmask);
+
+ while (dotcnt < 4) {
+ (void)lex_token_append(token, 2, ".0");
+ ++dotcnt;
+ }
+ break;
+ }
+ else {
+ /* Append the "." to the token string */
+ (void)lex_token_append(token, 1, ".");
+ }
+ }
+
+ /* Get a pointer to the token string */
+ tokenstr = lex_token(token);
+
+ /* A NULL pointer or an empty string is an error */
+ if (!tokenstr || !*tokenstr) goto err_noip;
+
+ /* Convert IP address to binary */
+ ipaddr = inet_addr(tokenstr);
+ if (ipaddr == (unsigned long)-1) goto err_badip;
+
+ /* Skip whitespace */
+ rv = lex_skip_over(lst, aclChTab, CCM_WS);
+ if (rv < 0) goto err_lex2;
+
+ /* A digit is the start of a netmask */
+ if ((netmask == 0xffffffff) && lex_class_check(aclChTab, rv, CCM_DIGIT)) {
+
+ /* Initialize token for network mask */
+ rv = lex_token_start(token);
+
+ for (dotcnt = 0;;) {
+
+ /* Collect token including digits, letters, and periods */
+ rv = lex_scan_over(lst, aclChTab, (CCM_DIGIT|CCM_LETTER), token);
+ if (rv < 0) goto err_lex3;
+
+ /* Stop when no "." follows the digits and letters */
+ if (rv != '.') break;
+
+ /* Stop if we've already seen three "." */
+ if (++dotcnt > 3) break;
+
+ /* Append the "." to the token string */
+ (void)lex_token_append(token, 1, ".");
+
+ /* Advance past the "." */
+ (void)lex_next_char(lst, aclChTab, CCM_SPECIAL);
+ }
+
+ /* Get a pointer to the token string */
+ tokenstr = lex_token(token);
+
+ /* A NULL pointer or an empty string is an error */
+ if (!tokenstr || !*tokenstr) goto err_nonm;
+
+ /* Convert netmask to binary. */
+ netmask = inet_addr(tokenstr);
+ if (netmask == (unsigned long)-1) {
+
+ /*
+ * Unfortunately inet_addr() doesn't distinguish between an
+ * error and a valid conversion of "255.255.255.255". So
+ * we check for it explicitly. Too bad if "0xff.0xff.0xff.0xff"
+ * is specified. Don't do that!
+ */
+ if (strcmp(tokenstr, "255.255.255.255")) goto err_badnm;
+ }
+ }
+
+ /* Return the IP address and netmask in host byte order */
+ *pip = ntohl(ipaddr);
+ *pmask = ntohl(netmask);
+
+ /* Get the token following the IP address (and netmask) */
+ rv = aclGetToken(errp, acf, 0);
+
+ punt:
+ acf->acf_ttype = (rv < 0) ? TOKEN_ERROR : rv;
+ return rv;
+
+ err_lex1:
+ eid = ACLERR2200;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_lex2:
+ eid = ACLERR2220;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_lex3:
+ eid = ACLERR2240;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_noip:
+ eid = ACLERR2260;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_badip:
+ eid = ACLERR2280;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_nonm:
+ eid = ACLERR2300;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_badnm:
+ eid = ACLERR2320;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_ret:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+ goto punt;
+}
+
+/*
+ * Description (aclGetToken)
+ *
+ * This function retrieves the next token in an ACL definition file.
+ * It skips blank lines, comments, and white space. It updates
+ * the current line number as newlines are encountered.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * flags - bit flags:
+ * AGT_NOSKIP - don't skip leading whitespace
+ * AGT_APPEND - append to token buffer
+ * (else start new token)
+ *
+ * Returns:
+ *
+ * The return value is a code identifying the next token if successful.
+ * This token type value is also returned in acf_ttype. An error
+ * is indicated by a negative error code (ACLERRxxxx - see aclerror.h),
+ * and an error frame will be generated if an error list is provided.
+ * The token type code in acf_ttype is TOKEN_ERROR when an error code
+ * is returned.
+ */
+
+int aclGetToken(NSErr_t * errp, ACLFile_t * acf, int flags)
+{
+ LEXStream_t * lst = acf->acf_lst; /* LEX stream handle */
+ void * token = acf->acf_token; /* LEX token handle */
+ int dospecial = 0; /* handle CCM_SPECIAL character */
+ int tv; /* token value */
+ int rv; /* result value */
+ int eid; /* error id */
+ char spech;
+ char linestr[16]; /* line number string buffer */
+
+ /* Begin a new token, unless AGT_APPEND is set */
+ if (!(flags & AGT_APPEND)) {
+ rv = lex_token_start(token);
+ }
+
+ /* Loop to read file */
+ tv = 0;
+ do {
+
+ /*
+ * If the AGT_NOSKIP flag is not set, skip whitespace (but not
+ * newline). If the flag is set, just get the next character.
+ */
+ rv = lex_skip_over(lst, aclChTab, (flags & AGT_NOSKIP) ? 0 : CCM_WS);
+ if (rv <= 0) {
+ if (rv < 0) goto err_lex1;
+
+ /* Exit loop if EOF */
+ if (rv == 0) {
+ tv = TOKEN_EOF;
+ break;
+ }
+ }
+
+ /* Analyze character after whitespace */
+ switch (rv) {
+
+ case '\n': /* newline */
+
+ /* Keep count of lines as we're skipping whitespace */
+ acf->acf_lineno += 1;
+ (void)lex_next_char(lst, aclChTab, CCM_NL);
+ break;
+
+ case '#': /* Beginning of comment */
+
+ /* Skip to a newline if so */
+ rv = lex_skip_to(lst, aclChTab, CCM_NL);
+ break;
+
+ case ';': /* End of statement */
+ tv = TOKEN_EOS;
+ dospecial = 1;
+ break;
+
+ case '@': /* at sign */
+ tv = TOKEN_AT;
+ dospecial = 1;
+ break;
+
+ case '+': /* plus sign */
+ tv = TOKEN_PLUS;
+ dospecial = 1;
+ break;
+
+ case '*': /* asterisk */
+ tv = TOKEN_STAR;
+ dospecial = 1;
+ break;
+
+ case '.': /* period */
+ tv = TOKEN_PERIOD;
+ dospecial = 1;
+ break;
+
+ case ',': /* comma */
+ tv = TOKEN_COMMA;
+ dospecial = 1;
+ break;
+
+ case '(': /* left parenthesis */
+ tv = TOKEN_LPAREN;
+ dospecial = 1;
+ break;
+
+ case ')': /* right parenthesis */
+ tv = TOKEN_RPAREN;
+ dospecial = 1;
+ break;
+
+ case '{': /* left brace */
+ tv = TOKEN_LBRACE;
+ dospecial = 1;
+ break;
+
+ case '}': /* right brace */
+ tv = TOKEN_RBRACE;
+ dospecial = 1;
+ break;
+
+ case '\"': /* double quote */
+ case '\'': /* single quote */
+
+ /* Append string contents to token buffer */
+ rv = lex_scan_string(lst, token, 0);
+ tv = TOKEN_STRING;
+ break;
+
+ default:
+
+ /* Check for identifier, beginning with a letter */
+ if (lex_class_check(aclChTab, rv, CCM_LETTER)) {
+
+ /* Append valid identifier characters to token buffer */
+ rv = lex_scan_over(lst, aclChTab, CCM_IDENT, token);
+ tv = TOKEN_IDENT;
+ break;
+ }
+
+ /* Check for a number, beginning with a digit */
+ if (lex_class_check(aclChTab, rv, CCM_DIGIT)) {
+ char digit;
+
+ /* Save the first digit */
+ digit = (char)rv;
+
+ /* Append the first digit to the token */
+ rv = lex_token_append(token, 1, &digit);
+
+ /* Skip over the first digit */
+ rv = lex_next_char(lst, aclChTab, CCM_DIGIT);
+
+ /* If it's '0', we might have "0x.." */
+ if (rv == '0') {
+
+ /* Pick up the next character */
+ rv = lex_next_char(lst, aclChTab, 0);
+
+ /* Is it 'x'? */
+ if (rv == 'x') {
+
+ /* Yes, append it to the token */
+ digit = (char)rv;
+ rv = lex_token_append(token, 1, &digit);
+
+ /* Step over it */
+ rv = lex_next_char(lst, aclChTab, CCM_LETTER);
+ }
+ }
+ /* Get more digits, if any */
+ rv = lex_scan_over(lst, aclChTab, CCM_DIGIT, token);
+ tv = TOKEN_NUMBER;
+ break;
+ }
+
+ /* Unrecognized character */
+
+ spech = *lst->lst_cp;
+ lex_token_append(token, 1, &spech);
+ lst->lst_cp += 1;
+ lst->lst_len -= 1;
+ tv = TOKEN_HUH;
+ break;
+ }
+
+ /* Handle CCM_SPECIAL character? */
+ if (dospecial) {
+
+ /* Yes, clear the flag for next time */
+ dospecial = 0;
+
+ /* Get the character and advance past it */
+ rv = lex_next_char(lst, aclChTab, CCM_SPECIAL);
+
+ /* Append the character to the token buffer */
+ spech = (char)rv;
+ (void)lex_token_append(token, 1, &spech);
+ }
+ }
+ while ((tv == 0) && (rv > 0));
+
+ if (rv < 0) {
+ tv = TOKEN_ERROR;
+ }
+ else rv = tv;
+
+ acf->acf_ttype = tv;
+ return rv;
+
+ err_lex1:
+ rv = ACLERRPARSE;
+ eid = ACLERR2400;
+
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+
+ acf->acf_ttype = TOKEN_ERROR;
+ return rv;
+}
+
+/*
+ * Description (aclParseInit)
+ *
+ * This function is called to initialize the ACL parser. It
+ * creates a LEX character class table to assist in parsing.
+ *
+ * Arguments:
+ *
+ * None.
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. An error is indicated
+ * by a negative return value.
+ */
+
+int aclParseInit()
+{
+ int rv; /* result value */
+
+ /* Have we created the character class table yet? */
+ if (aclChTab == 0) {
+
+ /* No, initialize character classes for lexer processing */
+ rv = lex_class_create(classc, classv, &aclChTab);
+ if (rv < 0) goto err_nomem;
+ }
+
+ return 0;
+
+ err_nomem:
+ return ACLERRNOMEM;
+}
+
+/*
+ * Description (aclRealmSpecParse)
+ *
+ * This function parses an authentication realm specification. An
+ * authentication realm includes an authentication database and
+ * an authentication method. The syntax of a realm-spec is:
+ *
+ * realm-spec ::= "{" realm-directive-list "}" | "realm" realm-name
+ * realm-directive-list ::= realm-directive |
+ * realm-directive-list ";" realm-directive
+ * realm-directive ::= realm-db-directive | realm-meth-directive
+ * | realm-prompt-directive
+ * realm-db-directive ::= "database" db-file-path
+ * realm-meth-directive ::= "method" auth-method-name
+ * auth-method-name ::= "basic" | "SSL"
+ * realm-prompt-directive ::= "prompt" quote-char string quote-char
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * acc - pointer to ACContext_t structure
+ * rspp - pointer to RealmSpec_t pointer
+ *
+ * Returns:
+ *
+ * If successful, the return value is the token type of the token
+ * following the realm-spec, i.e. either the first token after a
+ * realm-name or the first token after the closing "}". It is the
+ * caller's responsibility to validate this token as a legitimate
+ * successor of a realm-spec. If a parsing error occurs in the
+ * middle of a realm-spec, the return value is ACLERRPARSE, and an
+ * error frame is generated if an error list is provided. For
+ * other kinds of errors a negative error code (from aclerror.h)
+ * is returned.
+ */
+
+int aclRealmSpecParse(NSErr_t * errp,
+ ACLFile_t * acf, ACContext_t * acc, RealmSpec_t **rspp)
+{
+ void * token = acf->acf_token; /* handle for current token */
+ char * tokenstr; /* current token string */
+ RealmSpec_t * rsp; /* realm spec pointer */
+ RealmSpec_t * nrsp; /* named realm spec pointer */
+ int rv; /* result value */
+ int eid; /* error id value */
+ char linestr[16]; /* line number string buffer */
+
+ rv = acf->acf_ttype;
+
+ /* Is the current token a "{" ? */
+ if (rv != TOKEN_LBRACE) {
+
+ /* No, could it be KEYWORD_REALM? */
+ if (rv == TOKEN_IDENT) {
+
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_REALM)) {
+
+ /* Yes, step to the realm name */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv != TOKEN_IDENT) {
+ if (rv < 0) goto punt;
+ goto err_rlmname;
+ }
+
+ tokenstr = lex_token(token);
+
+ /* Look up the named realm specification */
+ rv = symTableFindSym(acc->acc_stp, tokenstr, ACLSYMREALM,
+ (void **)&nrsp);
+ if (rv < 0) goto err_undrlm;
+
+ /* Return the named realm specification */
+ *rspp = nrsp;
+
+ /* Step to the token after the realm name */
+ rv = aclGetToken(errp, acf, 0);
+ }
+ }
+
+ return rv;
+ }
+
+ /* Step to the token after the "{" */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+
+ rsp = *rspp;
+ if (rsp == 0) {
+ rsp = (RealmSpec_t *)MALLOC(sizeof(RealmSpec_t));
+ if (rsp == 0) goto err_nomem;
+ memset((void *)rsp, 0, sizeof(RealmSpec_t));
+ rsp->rs_sym.sym_type = ACLSYMREALM;
+ *rspp = rsp;
+ }
+
+ /* Loop for each realm-directive */
+ for (;; rv = aclGetToken(errp, acf, 0)) {
+
+ if (rv != TOKEN_IDENT) {
+
+ /* Exit loop on "}" */
+ if (rv == TOKEN_RBRACE) break;
+
+ /* Ignore null directives */
+ if (rv == TOKEN_EOS) continue;
+
+ /* Otherwise need an identifier to start a directive */
+ goto err_nodir;
+ }
+
+ tokenstr = lex_token(token);
+
+ /* Figure out which realm-directive this is */
+ if (!strcasecmp(tokenstr, KEYWORD_DATABASE)) {
+
+ /* Get a file specification for the database */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv != TOKEN_STRING) {
+ if (rv < 0) goto punt;
+ goto err_nodb;
+ }
+
+ rsp->rs_realm.rlm_dbname = lex_token_take(token);
+ rsp->rs_realm.rlm_aif = &NSADB_AuthIF;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_METHOD)) {
+
+ /* Step to the method identifier */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv != TOKEN_IDENT) {
+ if (rv < 0) goto punt;
+ goto err_nometh;
+ }
+
+ tokenstr = lex_token(token);
+
+ /* Interpret method name and set method in realm structure */
+ if (!strcasecmp(tokenstr, KEYWORD_BASIC)) {
+ rsp->rs_realm.rlm_ameth = AUTH_METHOD_BASIC;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_SSL) && server_enterprise) {
+ rsp->rs_realm.rlm_ameth = AUTH_METHOD_SSL;
+ }
+ else goto err_badmeth;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_PROMPT)) {
+
+ /* Step to the realm prompt string */
+ rv = aclGetToken(errp, acf, 0);
+ if ((rv != TOKEN_STRING) && (rv != TOKEN_IDENT)) {
+ if (rv < 0) goto punt;
+ goto err_noprompt;
+ }
+
+ /* Reference a copy of the prompt string from the realm */
+ rsp->rs_realm.rlm_prompt = lex_token_take(token);
+ }
+ else goto err_baddir;
+
+ /* Get the token after the realm-directive */
+ rv = aclGetToken(errp, acf, 0);
+
+ /* Need a ";" to keep going */
+ if (rv != TOKEN_EOS) break;
+ }
+
+ if (rv != TOKEN_RBRACE) goto err_rbrace;
+
+ /* Get the token after the realm-spec */
+ rv = aclGetToken(errp, acf, 0);
+
+ punt:
+ return rv;
+
+ err_rlmname:
+ eid = ACLERR2500;
+ goto err_parse;
+
+ err_undrlm:
+ eid = ACLERR2520;
+ rv = ACLERRUNDEF;
+ goto err_sym;
+
+ err_nomem:
+ eid = ACLERR2540;
+ rv = ACLERRNOMEM;
+ goto ret_err;
+
+ err_nodir:
+ eid = ACLERR2560;
+ goto err_parse;
+
+ err_nodb:
+ eid = ACLERR2570;
+ goto err_parse;
+
+ err_nometh:
+ eid = ACLERR2580;
+ goto err_parse;
+
+ err_badmeth:
+ eid = ACLERR2600;
+ goto err_sym;
+
+ err_noprompt:
+ eid = ACLERR2605;
+ goto err_parse;
+
+ err_baddir:
+ eid = ACLERR2610;
+ goto err_sym;
+
+ err_rbrace:
+ eid = ACLERR2620;
+ goto err_parse;
+
+ err_sym:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 3, acf->acf_filename, linestr, tokenstr);
+ goto punt;
+
+ err_parse:
+ rv = ACLERRPARSE;
+ ret_err:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+ goto punt;
+}
+
+/*
+ * Description (aclRightsParse)
+ *
+ * This function parse an access rights list. The syntax for an
+ * access rights list is:
+ *
+ * rights-list ::= "(" list-of-rights ")"
+ * list-of-rights ::= rights-elem | list-of-rights "," rights-elem
+ * rights-elem ::= right-name | "+" rights-def-name
+ * right-name ::= identifier
+ * rights-def-name ::= identifier
+ *
+ * An element of a rights list is either the name of a particular
+ * access right (e.g. Read), or the name associated with an
+ * external definition of an access rights list, preceded by "+"
+ * (e.g. +editor-rights). The list is enclosed in parentheses,
+ * and the elements are separated by commas.
+ *
+ * This function adds to a list of rights provided by the caller.
+ * Access rights are internally assigned unique integer identifiers,
+ * and a symbol table is maintained to map an access right name to
+ * its identifier.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * acc - pointer to ACContext_t structure
+ * rights - pointer to rights list head
+ *
+ * Returns:
+ *
+ * The return value is a code identifying the next token if successful.
+ * End-of-stream is indicated by a return value of TOKEN_EOF. An error
+ * is indicated by a negative error code (ACLERRxxxx - see aclerror.h),
+ * and an error frame will be generated if an error list is provided.
+ */
+
+int aclRightsParse(NSErr_t * errp, ACLFile_t * acf, ACContext_t * acc,
+ RightSpec_t **rights)
+{
+ void * token = acf->acf_token; /* LEX token handle */
+ char * ename; /* element name string pointer */
+ RightSpec_t * rsp; /* rights specification pointer */
+ RightSpec_t * nrsp; /* named rights spec pointer */
+ RightDef_t * rdp; /* right definition pointer */
+ int rv; /* result value */
+ int eid; /* error id */
+ char linestr[16]; /* line number string buffer */
+
+ /* Look for a left parenthesis */
+ if (acf->acf_ttype != TOKEN_LPAREN) {
+
+ /* No rights list present */
+ return 0;
+ }
+
+ rsp = *rights;
+
+ /* Create a RightSpec_t if we don't have one */
+ if (rsp == 0) {
+ rsp = (RightSpec_t *)MALLOC(sizeof(RightSpec_t));
+ if (rsp == 0) goto err_nomem1;
+ memset((void *)rsp, 0, sizeof(RightSpec_t));
+ rsp->rs_sym.sym_type = ACLSYMRDEF;
+ *rights = rsp;
+ }
+
+ /* Parse list elements */
+ for (;;) {
+
+ /* Look for an identifier */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv != TOKEN_IDENT) {
+
+ /* No, maybe a "+" preceding a rights definition name? */
+ if (rv != TOKEN_PLUS) {
+
+ /* One more chance, we'll allow the closing ")" after "," */
+ if (rv != TOKEN_RPAREN) {
+ /* No, bad news */
+ if (rv < 0) goto punt;
+ goto err_elem;
+ }
+
+ /* Got right paren after comma */
+ break;
+ }
+
+ /* Got a "+", try for the rights definition name */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv != TOKEN_IDENT) {
+ if (rv < 0) goto punt;
+ goto err_rdef;
+ }
+
+ /* Get a pointer to the token string */
+ ename = lex_token(token);
+
+ /* See if it matches a rights definition in the symbol table */
+ rv = symTableFindSym(acc->acc_stp, ename, ACLSYMRDEF,
+ (void **)&nrsp);
+ if (rv) goto err_undef;
+
+ /*
+ * Merge the rights from the named rights list into the
+ * current rights list.
+ */
+ rv = uilMerge(&rsp->rs_list, &nrsp->rs_list);
+ if (rv < 0) goto err_nomem2;
+ }
+ else {
+
+ /* The current token is an access right name */
+
+ /* Get a pointer to the token string */
+ ename = lex_token(token);
+
+
+ /* Find or create an access right definition */
+ rv = aclRightDef(errp, acc, ename, &rdp);
+ if (rv < 0) goto err_radd;
+
+ /* Add the id for this right to the current rights list */
+ rv = usiInsert(&rsp->rs_list, rdp->rd_id);
+ if (rv < 0) goto err_nomem3;
+ }
+
+ rv = aclGetToken(errp, acf, 0);
+
+ /* Want a comma to continue the list */
+ if (rv != TOKEN_COMMA) {
+
+ /* A right parenthesis will end the list nicely */
+ if (rv == TOKEN_RPAREN) {
+
+ /* Get the first token after the rights list */
+ rv = aclGetToken(errp, acf, 0);
+ break;
+ }
+
+ /* Anything else is an error */
+ if (rv < 0) goto punt;
+ goto err_list;
+ }
+ }
+
+ return rv;
+
+ err_elem:
+ eid = ACLERR2700;
+ rv = ACLERRSYNTAX;
+ goto err_ret;
+
+ err_rdef:
+ eid = ACLERR2720;
+ rv = ACLERRSYNTAX;
+ goto err_ret;
+
+ err_undef:
+ eid = ACLERR2740;
+ rv = ACLERRUNDEF;
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 3, acf->acf_filename, linestr, ename);
+ return rv;
+
+ err_nomem1:
+ eid = ACLERR2760;
+ goto err_nomem;
+
+ err_nomem2:
+ eid = ACLERR2780;
+ goto err_nomem;
+
+ err_radd:
+ eid = ACLERR2800;
+ goto err_ret;
+
+ err_nomem3:
+ eid = ACLERR2820;
+ goto err_nomem;
+
+ err_nomem:
+ rv = ACLERRNOMEM;
+ goto err_ret;
+
+ err_list:
+
+ eid = ACLERR2840;
+ rv = ACLERRSYNTAX;
+
+ err_ret:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (aclStreamGet)
+ *
+ * This function is the stream read function designated by
+ * aclFileOpen() to read the file associated with the LEX stream
+ * it creates. It reads the next chunk of the file into the
+ * stream buffer.
+ *
+ * Arguments:
+ *
+ * lst - pointer to LEX stream structure
+ *
+ * Returns:
+ *
+ * The return value is the number of bytes read if successful.
+ * A return value of zero indicates end-of-file. An error is
+ * indicated by a negative return value.
+ */
+
+int aclStreamGet(LEXStream_t * lst)
+{
+ SYS_FILE fd = (SYS_FILE)(lst->lst_strmid);
+ int len;
+
+ len = system_fread(fd, lst->lst_buf, lst->lst_buflen);
+ if (len >= 0) {
+ lst->lst_len = len;
+ lst->lst_cp = lst->lst_buf;
+ }
+
+ return len;
+}
diff --git a/lib/libaccess/aclpriv.h b/lib/libaccess/aclpriv.h
new file mode 100644
index 00000000..a93cc055
--- /dev/null
+++ b/lib/libaccess/aclpriv.h
@@ -0,0 +1,171 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * ACL private data structure definitions
+ */
+
+#ifndef ACL_PARSER_HEADER
+#define ACL_PARSER_HEADER
+
+#include <netsite.h>
+#include <plhash.h>
+#include <base/pool.h>
+#include <base/plist.h>
+#include <libaccess/las.h>
+
+
+#define ACL_TERM_BSIZE 4
+#define ACL_FALSE_IDX -2
+#define ACL_TRUE_IDX -1
+#define ACL_MIN_IDX 0
+#define ACL_EXPR_STACK 1024
+#define ACL_TABLE_THRESHOLD 10
+
+typedef enum {
+ ACL_EXPR_OP_AND,
+ ACL_EXPR_OP_OR,
+ ACL_EXPR_OP_NOT
+ } ACLExprOp_t;
+
+
+typedef struct ACLExprEntry {
+ char *attr_name; /* LAS name input */
+ CmpOp_t comparator; /* LAS comparator input */
+ char *attr_pattern; /* LAS attribute input */
+ int false_idx; /* index, -1 true, -2 false */
+ int true_idx; /* index, -1 true, -2 false */
+ int start_flag; /* marks start of an expr */
+ void *las_cookie; /* private data store for LAS */
+ LASEvalFunc_t las_eval_func; /* LAS function */
+} ACLExprEntry_t;
+
+typedef struct ACLExprRaw {
+ char *attr_name; /* expr lval */
+ CmpOp_t comparator; /* comparator */
+ char *attr_pattern; /* expr rval */
+ ACLExprOp_t logical; /* logical operator */
+} ACLExprRaw_t;
+
+typedef struct ACLExprStack {
+ char *expr_text[ACL_EXPR_STACK];
+ ACLExprRaw_t *expr[ACL_EXPR_STACK];
+ int stack_index;
+ int found_subexpression;
+ int last_subexpression;
+} ACLExprStack_t;
+
+typedef struct ACLExprHandle {
+ char *expr_tag;
+ char *acl_tag;
+ int expr_number;
+ ACLExprType_t expr_type;
+ int expr_flags;
+ int expr_argc;
+ char **expr_argv;
+ PList_t expr_auth;
+ ACLExprEntry_t *expr_arry;
+ int expr_arry_size;
+ int expr_term_index;
+ ACLExprRaw_t *expr_raw;
+ int expr_raw_index;
+ int expr_raw_size;
+ struct ACLExprHandle *expr_next; /* Null-terminated */
+} ACLExprHandle_t;
+
+typedef struct ACLHandle {
+ int ref_count;
+ char *tag;
+ PFlags_t flags;
+ char *las_name;
+ pblock *pb;
+ char **attr_name;
+ int expr_count;
+ ACLExprHandle_t *expr_list_head; /* Null-terminated */
+ ACLExprHandle_t *expr_list_tail;
+} ACLHandle_t;
+
+
+typedef struct ACLWrapper {
+ ACLHandle_t *acl;
+ struct ACLWrapper *wrap_next;
+} ACLWrapper_t;
+
+#define ACL_LIST_STALE 0x1
+#define ACL_LIST_IS_STALE(x) ((x)->flags & ACL_LIST_STALE)
+
+typedef struct ACLListHandle {
+ ACLWrapper_t *acl_list_head; /* Null-terminated */
+ ACLWrapper_t *acl_list_tail; /* Null-terminated */
+ int acl_count;
+ void *acl_sym_table;
+ void *cache;
+ uint32 flags;
+ int ref_count;
+} ACLListHandle_t;
+
+typedef struct ACLAceNumEntry {
+ int acenum;
+ struct ACLAceNumEntry *next;
+ struct ACLAceNumEntry *chain; /* only used for freeing memory */
+} ACLAceNumEntry_t;
+
+typedef struct ACLAceEntry {
+ ACLExprHandle_t *acep;
+ /* Array of auth block ptrs for all the expr
+ clauses in this ACE */
+ PList_t *autharray;
+ /* PList with auth blocks for ALL attributes */
+ PList_t global_auth;
+ struct ACLAceEntry *next; /* Null-terminated list */
+} ACLAceEntry_t;
+
+typedef struct PropList PropList_t;
+
+typedef struct ACLEvalHandle {
+ pool_handle_t *pool;
+ ACLListHandle_t *acllist;
+ PList_t subject;
+ PList_t resource;
+ int default_result;
+} ACLEvalHandle_t;
+
+
+typedef struct ACLListCache {
+/* Hash table for all access rights used in all acls in this list. Each
+ * hash entry has a list of ACE numbers that relate to this referenced
+ * access right.
+ */
+ PLHashTable *Table;
+ char *deny_response;
+ char *deny_type;
+ ACLAceEntry_t *acelist; /* Evaluation order
+ * list of all ACEs
+ */
+ ACLAceNumEntry_t *chain_head; /* Chain of all Ace num
+ * entries for this
+ * ACL list so we can free them
+ */
+ ACLAceNumEntry_t *chain_tail;
+} ACLListCache_t;
+
+/* this is to speed up acl_to_str_append */
+typedef struct acl_string_s {
+ char * str;
+ long str_size;
+ long str_len;
+} acl_string_t;
+
+
+
+NSPR_BEGIN_EXTERN_C
+extern int ACL_ExprDisplay( ACLExprHandle_t *acl_expr );
+extern int ACL_AssertAcl( ACLHandle_t *acl );
+extern int ACL_EvalDestroyContext ( ACLListCache_t *cache );
+extern time_t *acl_get_req_time(PList_t resource);
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/aclscan.h b/lib/libaccess/aclscan.h
new file mode 100644
index 00000000..df54f374
--- /dev/null
+++ b/lib/libaccess/aclscan.h
@@ -0,0 +1,25 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Internal functions for scanner.
+ */
+
+
+#ifndef ACLSCAN_H
+#define ACLSCAN_H
+
+NSPR_BEGIN_EXTERN_C
+
+extern int acl_InitScanner(NSErr_t *errp, char *filename, char *buffer);
+extern int acl_EndScanner(void);
+extern void aclerror(const char *s);
+extern int acllex(void);
+
+NSPR_END_EXTERN_C
+
+#endif
+
diff --git a/lib/libaccess/aclscan.l b/lib/libaccess/aclscan.l
new file mode 100644
index 00000000..009e02db
--- /dev/null
+++ b/lib/libaccess/aclscan.l
@@ -0,0 +1,379 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Lexical analyzer for ACL
+ */
+
+%{
+#include "acl.tab.h" /* token codes */
+#include <base/file.h>
+#include <libaccess/acl.h>
+#include <libaccess/nserror.h>
+#include "aclpriv.h"
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <libaccess/aclerror.h>
+#ifdef XP_WIN32
+#include <io.h>
+#endif
+
+#include "parse.h"
+#include "aclscan.h"
+
+static int acl_scanner_input(char *buffer, int max_size);
+
+#define YY_NEVER_INTERACTIVE 1
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max) (result = acl_scanner_input(buf, max))
+
+static int acl_lineno;
+static int acl_tokenpos;
+static char acl_filename[500];
+static NSErr_t *acl_errp;
+static int acl_use_buffer;
+static char *acl_buffer;
+static int acl_buffer_length;
+static int acl_buffer_offset;
+static char *last_string;
+static SYS_FILE acl_prfd;
+
+
+%}
+
+ws [ \t]+
+comment #.*
+qstring \"[^\"\n]*[\"\n]
+variable [\*a-zA-Z0-9\.\-\_][\*a-zA-Z0-9\.\-\_]*
+
+%%
+
+\n.* {
+ acl_lineno++;
+ acl_tokenpos = 0;
+ yyless(1);
+ }
+
+{ws} ;
+
+{comment} ;
+
+<<EOF>> {
+ yylval.string = NULL;
+ last_string = yylval.string;
+ return(0);
+ }
+
+{qstring} {
+ yylval.string = PERM_STRDUP( yytext+1 );
+ last_string = yylval.string;
+ if ( yylval.string[yyleng-2] != '"' )
+ fprintf(stderr, "Unterminated string\n") ;
+ else
+ yylval.string[yyleng-2] = '\0';
+ acl_tokenpos += yyleng;
+ return ACL_QSTRING_TOK;
+ }
+
+
+absolute {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_ABSOLUTE_TOK;
+ }
+
+acl {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_ACL_TOK;
+ }
+
+allow {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_ALLOW_TOK;
+ }
+
+always {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_ALWAYS_TOK;
+ }
+
+at {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_AT_TOK;
+ }
+
+authenticate {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_AUTHENTICATE_TOK;
+ }
+
+content {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_CONTENT_TOK;
+ }
+
+default {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_DEFAULT_TOK;
+ }
+
+deny {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_DENY_TOK;
+ }
+
+in {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_IN_TOK;
+ }
+
+inherit {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_INHERIT_TOK;
+ }
+
+terminal {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_TERMINAL_TOK;
+ }
+
+version {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_VERSION_TOK;
+ }
+
+with {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_WITH_TOK;
+ }
+
+not {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_NOT_TOK;
+ }
+
+and {
+ last_string = NULL;
+ yylval.ival = ACL_EXPR_OP_AND;
+ acl_tokenpos += yyleng;
+ return ACL_AND_TOK;
+ }
+
+or {
+ last_string = NULL;
+ yylval.ival = ACL_EXPR_OP_OR;
+ acl_tokenpos += yyleng;
+ return ACL_OR_TOK;
+ }
+
+"=" {
+ last_string = NULL;
+ yylval.ival = CMP_OP_EQ;
+ acl_tokenpos += yyleng;
+ return ACL_EQ_TOK;
+ }
+
+">=" {
+ last_string = NULL;
+ yylval.ival = CMP_OP_GE;
+ acl_tokenpos += yyleng;
+ return ACL_GE_TOK;
+ }
+
+">" {
+ last_string = NULL;
+ yylval.ival = CMP_OP_GT;
+ acl_tokenpos += yyleng;
+ return ACL_GT_TOK;
+ }
+
+"<" {
+ last_string = NULL;
+ yylval.ival = CMP_OP_LT;
+ acl_tokenpos += yyleng;
+ return ACL_LT_TOK;
+ }
+
+"<=" {
+ last_string = NULL;
+ yylval.ival = CMP_OP_LE;
+ acl_tokenpos += yyleng;
+ return ACL_LE_TOK;
+ }
+
+"!=" {
+ last_string = NULL;
+ yylval.ival = CMP_OP_NE;
+ acl_tokenpos += yyleng;
+ return ACL_NE_TOK;
+ }
+
+[(){},;] {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return yytext[0];
+ }
+
+{variable} {
+ acl_tokenpos += yyleng;
+ yylval.string = PERM_STRDUP( yytext );
+ last_string = yylval.string;
+ return ACL_VARIABLE_TOK;
+ }
+%%
+
+void
+acl_detab(char *t, char *s)
+{
+ int ii;
+ int pos;
+ int len;
+
+ if (s == NULL || t == NULL)
+ return;
+
+ len = strlen(s);
+ pos = 0;
+ for (ii = 0; ii < len; ii++) {
+ if (s[ii] == '\t') {
+ t[pos] = ' ';
+ } else {
+ t[pos] = s[ii];
+ }
+ pos++;
+ }
+ t[pos] = '\0';
+ return;
+}
+
+void
+yyerror(const char *s)
+{
+char errorStr[256];
+
+#if defined(UTEST) || defined(ACL_COMPILER)
+ printf("ACL file: %s\n", acl_filename);
+ printf("Syntax error at line: %d, token: %s\n", acl_lineno, yytext);
+ if ( last_string )
+ free(last_string);
+#else
+ sprintf(errorStr, "%d", acl_lineno);
+ if (yytext) {
+ nserrGenerate(acl_errp, ACLERRPARSE, ACLERR1780, ACL_Program,
+ 3, acl_filename, errorStr, yytext);
+ } else {
+ nserrGenerate(acl_errp, ACLERRPARSE, ACLERR1780, ACL_Program,
+ 2, acl_filename, errorStr);
+ }
+ if ( last_string )
+ free(last_string);
+#endif
+
+}
+
+int
+acl_InitScanner(NSErr_t *errp, char *filename, char *buffer)
+{
+ acl_errp = errp;
+ acl_lineno = 1;
+ acl_use_buffer = (filename == NULL) ? 1 : 0 ;
+ if ( filename != NULL ) {
+ strcpy(acl_filename, filename);
+#ifdef UTEST
+ yyin = fopen(filename, "r");
+ if ( yyin == NULL ) {
+ return(-1);
+ }
+#else
+ acl_prfd = system_fopenRO(filename);
+ if ( acl_prfd == NULL ) {
+ return(-1);
+ }
+ yyin = (FILE *) acl_prfd;
+#endif
+ yyrestart(yyin);
+ } else if ( buffer != NULL ) {
+ strcpy(acl_filename, "internal-buffer");
+ acl_buffer_offset = 0;
+ acl_buffer_length = strlen(buffer);
+ acl_buffer = PERM_STRDUP(buffer);
+ if (acl_buffer == NULL)
+ return(-1);
+ yyrestart(NULL);
+ } else {
+ return(-1);
+ }
+ return(0);
+}
+
+int
+acl_EndScanner()
+{
+ acl_lineno = 0;
+ if ( acl_use_buffer) {
+ if ( acl_buffer )
+ PERM_FREE(acl_buffer);
+ } else if ( yyin ) {
+#ifdef UTEST
+ fclose(yyin);
+#else
+ if ( acl_prfd ) {
+ system_fclose(acl_prfd);
+ acl_prfd = NULL;
+ }
+#endif
+ yyin = NULL ;
+ }
+ return(0);
+}
+
+int
+yywrap()
+{
+ return(1);
+}
+
+static int
+acl_scanner_input(char *buffer, int max_size)
+{
+ int len = 0;
+
+ if ( acl_use_buffer ) {
+ len = (acl_buffer_length > max_size) ? max_size :
+ acl_buffer_length;
+ memcpy(buffer, (const void *) &acl_buffer[acl_buffer_offset],
+ len);
+ acl_buffer_length -= len;
+ acl_buffer_offset += len;
+ }
+#ifdef UTEST
+ else if ( ((len = fread( buffer, 1, max_size, aclin )) == 0)
+ && ferror( aclin ) ) {
+ yyerror( "scanner input failed" );
+ }
+#else
+ else if ( (len = system_fread( acl_prfd, buffer, max_size)) < 0 ) {
+ yyerror( "scanner input failed" );
+ }
+#endif
+
+ return(len);
+}
diff --git a/lib/libaccess/aclspace.cpp b/lib/libaccess/aclspace.cpp
new file mode 100644
index 00000000..fb211075
--- /dev/null
+++ b/lib/libaccess/aclspace.cpp
@@ -0,0 +1,37 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <string.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclglobal.h>
+
+/* Ordered list of generic rights */
+char *generic_rights[7] = {
+ "read",
+ "write",
+ "execute",
+ "delete",
+ "info",
+ "list",
+ NULL
+ } ;
+
+char *http_generic[7] = {
+ "http_get, http_head, http_trace, http_revlog, http_options, http_copy, http_getattribute, http_index, http_getproperties, http_getattributenames ",
+ "http_put, http_mkdir, http_startrev, http_stoprev, http_edit, http_post, http_save, http_setattribute, http_revadd, http_revlabel, http_lock, http_unlock, http_unedit, http_stoprev, http_startrev",
+ "http_post",
+ "http_delete, http_destroy, http_move",
+ "http_head, http_trace, http_options",
+ "http_index",
+ NULL
+ } ;
+
+/* Pointer to all global ACL data. This pointer is moved (atomically)
+ when a cache flush call is made.
+*/
+ACLGlobal_p ACLGlobal;
+ACLGlobal_p oldACLGlobal;
diff --git a/lib/libaccess/acltext.y b/lib/libaccess/acltext.y
new file mode 100644
index 00000000..01d6ae1f
--- /dev/null
+++ b/lib/libaccess/acltext.y
@@ -0,0 +1,957 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * This grammar is intended to parse the version 3.0
+ * and version 2.0 ACL text files and output an ACLListHandle_t
+ * structure.
+ */
+
+%{
+#include <string.h>
+#include <netsite.h>
+#include <base/util.h>
+#include <base/plist.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/nserror.h>
+#include "parse.h"
+#include "aclscan.h"
+
+#define MAX_LIST_SIZE 255
+static ACLListHandle_t *curr_acl_list; /* current acl list */
+static ACLHandle_t *curr_acl; /* current acl */
+static ACLExprHandle_t *curr_expr; /* current expression */
+static PFlags_t pflags; /* current authorization flags */
+static char *curr_args_list[MAX_LIST_SIZE]; /* current args */
+static char *curr_user_list[MAX_LIST_SIZE]; /* current users v2 */
+static char *curr_ip_dns_list[MAX_LIST_SIZE]; /* current ip/dns v2 */
+static PList_t curr_auth_info; /* current authorization method */
+static int use_generic_rights; /* use generic rights for conversion */
+
+int acl_PushListHandle(ACLListHandle_t *handle)
+{
+ curr_acl_list = handle;
+ return(0);
+}
+
+static void
+acl_string_lower(char *s)
+{
+int ii;
+int len;
+
+ len = strlen(s);
+ for (ii = 0; ii < len; ii++)
+ s[ii] = tolower(s[ii]);
+
+ return;
+}
+
+static void
+acl_clear_args(char **args_list)
+{
+ args_list[0] = NULL;
+}
+
+static void
+acl_add_arg(char **args_list, char *arg)
+{
+ static int args_index;
+
+ if ( args_list[0] == NULL ) {
+ args_index = 0;
+ }
+ args_list[args_index] = arg;
+ args_index++;
+ args_list[args_index] = NULL;
+}
+
+static void
+acl_free_args(char **args_list)
+{
+ int ii;
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( args_list[ii] )
+ free(args_list[ii]);
+ else
+ break;
+ }
+}
+
+static int
+acl_set_args(ACLExprHandle_t *expr, char **args_list)
+{
+ int ii;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( args_list[ii] ) {
+ if ( ACL_ExprAddArg(NULL, expr, args_list[ii]) < 0 ) {
+ yyerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+ } else
+ break;
+ }
+ return(0);
+}
+
+static int
+acl_set_users(ACLExprHandle_t *expr, char **user_list)
+{
+ int ii;
+ int jj;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( user_list[ii] ) {
+ if ( ACL_ExprTerm(NULL, expr, "user", CMP_OP_EQ,
+ user_list[ii]) < 0 ) {
+ yyerror("ACL_ExprTerm() failed");
+ acl_free_args(user_list);
+ return(-1);
+ }
+ } else
+ break;
+ }
+
+ acl_free_args(user_list);
+
+ for (jj = 0; jj < ii - 1; jj++) {
+ if ( ACL_ExprOr(NULL, expr) < 0 ) {
+ yyerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+static int
+acl_set_users_or_groups(ACLExprHandle_t *expr, char **user_list)
+{
+ int ii;
+ int jj;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( user_list[ii] ) {
+ if ( ACL_ExprTerm(NULL, expr, "user", CMP_OP_EQ,
+ user_list[ii]) < 0 ) {
+ yyerror("ACL_ExprTerm() failed");
+ acl_free_args(user_list);
+ return(-1);
+ }
+ if ( ACL_ExprTerm(NULL, expr, "group", CMP_OP_EQ,
+ user_list[ii]) < 0 ) {
+ yyerror("ACL_ExprTerm() failed");
+ acl_free_args(user_list);
+ return(-1);
+ }
+ } else
+ break;
+ }
+
+ acl_free_args(user_list);
+
+ for (jj = 0; jj < (ii * 2) - 1; jj++) {
+ if ( ACL_ExprOr(NULL, expr) < 0 ) {
+ yyerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+static int
+acl_set_ip_dns(ACLExprHandle_t *expr, char **ip_dns)
+{
+ int ii;
+ int jj;
+ int len;
+ char *attr;
+ char *val;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( ip_dns[ii] ) {
+
+ attr = "ip";
+ val = ip_dns[ii];
+ len = strlen(val);
+
+ for (jj = 0; jj < len; jj++) {
+ if ( strchr("0123456789.*", val[jj]) == 0 ) {
+ attr = "dns";
+ break;
+ }
+ }
+
+ if ( ACL_ExprTerm(NULL, expr, attr, CMP_OP_EQ,
+ val) < 0 ) {
+ yyerror("ACL_ExprTerm() failed");
+ acl_free_args(ip_dns);
+ return(-1);
+ }
+
+ } else
+ break;
+ }
+
+ acl_free_args(ip_dns);
+
+ for (jj = 0; jj < ii - 1; jj++) {
+ if ( ACL_ExprOr(NULL, expr) < 0 ) {
+ yyerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+
+ return(0);
+}
+
+
+%}
+
+%union {
+ char *string;
+ int ival;
+}
+
+%token ACL_ABSOLUTE_TOK
+%token ACL_ACL_TOK
+%token ACL_ALLOW_TOK
+%token ACL_ALWAYS_TOK
+%token ACL_AND_TOK
+%token ACL_AT_TOK
+%token ACL_AUTHENTICATE_TOK
+%token ACL_CONTENT_TOK
+%token ACL_DEFAULT_TOK
+%token ACL_DENY_TOK
+%token ACL_GROUP_TOK
+%token ACL_IN_TOK
+%token ACL_INHERIT_TOK
+%token ACL_NOT_TOK
+%token ACL_NULL_TOK
+%token ACL_OR_TOK
+%token <string> ACL_QSTRING_TOK
+%token ACL_READ_TOK
+%token ACL_TERMINAL_TOK
+%token <string> ACL_VARIABLE_TOK
+%token ACL_VERSION_TOK
+%token ACL_WRITE_TOK
+%token ACL_WITH_TOK
+
+%token <ival> ACL_EQ_TOK
+%token <ival> ACL_GE_TOK
+%token <ival> ACL_GT_TOK
+%token <ival> ACL_LE_TOK
+%token <ival> ACL_LT_TOK
+%token <ival> ACL_NE_TOK
+
+%%
+
+/*
+ * If no version is specified then we have a version 2.0 ACL.
+ */
+start: | start_acl_v2
+ | ACL_VERSION_TOK ACL_VARIABLE_TOK
+ {
+ free($<string>2);
+ }
+ ';' start_acl_v3
+ ;
+
+/*
+ ************************************************************
+ * Parse version 2.0 ACL
+ ************************************************************
+ */
+start_acl_v2: acl_list_v2
+ ;
+
+acl_list_v2: acl_v2
+ | acl_list_v2 acl_v2
+ ;
+
+acl_v2: ACL_ACL_TOK acl_name_v2
+ '(' arg_list_v2 ')' '{' directive_list_v2 '}'
+ {
+ acl_free_args(curr_args_list);
+ }
+ ;
+
+acl_name_v2: ACL_VARIABLE_TOK
+ {
+ curr_acl = ACL_AclNew(NULL, $<string>1);
+ free($<string>1);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ yyerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ acl_clear_args(curr_args_list);
+ use_generic_rights = 0;
+ if (strstr(curr_acl->tag, "READ")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("read"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("execute"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("list"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("info"));
+ } if (strstr(curr_acl->tag, "WRITE")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("write"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("delete"));
+ }
+ }
+ | ACL_QSTRING_TOK
+ {
+ curr_acl = ACL_AclNew(NULL, $<string>1);
+ free($<string>1);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ yyerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ acl_clear_args(curr_args_list);
+ use_generic_rights = 0;
+ if (strstr(curr_acl->tag, "READ")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("read"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("execute"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("list"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("info"));
+ } if (strstr(curr_acl->tag, "WRITE")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("write"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("delete"));
+ }
+ }
+ ;
+
+arg_list_v2: arg_v2
+ | arg_v2 ',' arg_list_v2
+ ;
+
+arg_v2: ACL_VARIABLE_TOK
+ {
+ char acl_tmp_arg[255];
+ char *acl_new_arg;
+
+ if (!use_generic_rights) {
+ acl_string_lower($<string>1);
+ strcpy(acl_tmp_arg, "http_");
+ strcat(acl_tmp_arg, $<string>1);
+ PERM_FREE($<string>1);
+ acl_new_arg = PERM_STRDUP(acl_tmp_arg);
+ acl_add_arg(curr_args_list, acl_new_arg);
+ } else {
+ PERM_FREE($<string>1);
+ }
+ }
+ | ACL_QSTRING_TOK
+ {
+ if (!use_generic_rights) {
+ acl_add_arg(curr_args_list, $<string>1);
+ } else {
+ PERM_FREE($<string>1);
+ }
+ }
+ ;
+
+directive_list_v2: directive_v2 ';'
+ | directive_v2 ';' directive_list_v2
+ ;
+
+directive_v2: auth_method_v2
+ | auth_statement_v2
+ ;
+
+auth_statement_v2: ACL_ALWAYS_TOK auth_type_v2
+ {
+ if ( ACL_ExprSetPFlags(NULL, curr_expr,
+ ACL_PFLAG_ABSOLUTE) < 0 ) {
+ yyerror("Could not set authorization processing flags");
+ return(-1);
+ }
+ }
+ host_spec_list_action_v2
+ | ACL_DEFAULT_TOK auth_type_v2 host_spec_list_action_v2
+ ;
+
+auth_type_v2: ACL_ALLOW_TOK
+ {
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_ALLOW) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ acl_clear_args(curr_user_list);
+ acl_clear_args(curr_ip_dns_list);
+ }
+ | ACL_DENY_TOK
+ {
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_DENY) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ acl_clear_args(curr_user_list);
+ acl_clear_args(curr_ip_dns_list);
+ }
+ ;
+
+auth_method_v2:
+ ACL_ALWAYS_TOK ACL_AUTHENTICATE_TOK ACL_IN_TOK
+ {
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_AUTH) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(auth) failed");
+ return(-1);
+ }
+ if ( ACL_ExprSetPFlags(NULL, curr_expr,
+ ACL_PFLAG_ABSOLUTE) < 0 ) {
+ yyerror("Could not set authorization processing flags");
+ return(-1);
+ }
+ curr_auth_info = PListCreate(NULL, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ if ( ACL_ExprAddAuthInfo(curr_expr, curr_auth_info) < 0 ) {
+ yyerror("Could not set authorization info");
+ return(-1);
+ }
+ }
+ realm_definition_v2
+ | ACL_DEFAULT_TOK ACL_AUTHENTICATE_TOK ACL_IN_TOK
+ {
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_AUTH) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(auth) failed");
+ return(-1);
+ }
+ curr_auth_info = PListCreate(NULL, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ if ( ACL_ExprAddAuthInfo(curr_expr, curr_auth_info) < 0 ) {
+ yyerror("Could not set authorization info");
+ return(-1);
+ }
+ }
+ realm_definition_v2
+ ;
+
+host_spec_list_action_v2: user_expr_v2 ACL_AT_TOK host_spec_list_v2
+ {
+ if ( acl_set_users_or_groups(curr_expr, curr_user_list) < 0 ) {
+ yyerror("acl_set_users_or_groups() failed");
+ return(-1);
+ }
+
+ if ( acl_set_ip_dns(curr_expr, curr_ip_dns_list) < 0 ) {
+ yyerror("acl_set_ip_dns() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAnd(NULL, curr_expr) < 0 ) {
+ yyerror("ACL_ExprAnd() failed");
+ return(-1);
+ }
+
+ if ( acl_set_args(curr_expr, curr_args_list) < 0 ) {
+ yyerror("acl_set_args() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ }
+ | user_expr_v2
+ {
+ if ( acl_set_users_or_groups(curr_expr, curr_user_list) < 0 ) {
+ yyerror("acl_set_users_or_groups() failed");
+ return(-1);
+ }
+
+ if ( acl_set_args(curr_expr, curr_args_list) < 0 ) {
+ yyerror("acl_set_args() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ }
+ ;
+
+user_expr_v2: user_v2
+ | '(' user_list_v2 ')'
+ ;
+
+user_list_v2: user_v2
+ | user_v2 ',' user_list_v2
+ ;
+
+user_v2: ACL_VARIABLE_TOK
+ {
+ acl_add_arg(curr_user_list, $<string>1);
+ }
+ | ACL_QSTRING_TOK
+ {
+ acl_add_arg(curr_user_list, $<string>1);
+ }
+ ;
+
+
+host_spec_list_v2: dns_spec_v2
+ | ip_spec_v2
+ | '(' dns_ip_spec_list_v2 ')'
+ ;
+
+dns_spec_v2: ACL_VARIABLE_TOK
+ {
+ acl_add_arg(curr_ip_dns_list, $<string>1);
+ }
+ | ACL_QSTRING_TOK
+ {
+ acl_add_arg(curr_ip_dns_list, $<string>1);
+ }
+ ;
+
+ip_spec_v2: ACL_VARIABLE_TOK ACL_VARIABLE_TOK
+ {
+ char tmp_str[255];
+
+ util_sprintf(tmp_str, "%s+%s", $<string>1, $<string>2);
+ free($<string>1);
+ free($<string>2);
+ acl_add_arg(curr_ip_dns_list, PERM_STRDUP(tmp_str));
+ }
+ ;
+
+dns_ip_spec_list_v2: dns_spec_v2
+ | ip_spec_v2
+ | dns_spec_v2 ',' dns_ip_spec_list_v2
+ | ip_spec_v2 ',' dns_ip_spec_list_v2
+ ;
+
+realm_definition_v2: '{' methods_list_v2 '}'
+ {
+ if ( ACL_ExprAddArg(NULL, curr_expr, "user") < 0 ) {
+ yyerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAddArg(NULL, curr_expr, "group") < 0 ) {
+ yyerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ }
+ ;
+
+method_v2: ACL_VARIABLE_TOK ACL_VARIABLE_TOK ';'
+ {
+ acl_string_lower($<string>1);
+ if (strcmp($<string>1, "database") == 0) {
+ free($<string>1);
+ free($<string>2);
+ } else {
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index($<string>1), $<string>1, $<string>2, NULL) < 0 ) {
+ }
+ free($<string>1);
+ }
+ }
+ | ACL_VARIABLE_TOK ACL_QSTRING_TOK ';'
+ {
+ acl_string_lower($<string>1);
+ if (strcmp($<string>1, "database") == 0) {
+ free($<string>1);
+ free($<string>2);
+ } else {
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index($<string>1), $<string>1, $<string>2, NULL) < 0 ) {
+ }
+ free($<string>1);
+ }
+ }
+ ;
+
+methods_list_v2: method_v2
+ | method_v2 methods_list_v2
+ ;
+
+/*
+ ************************************************************
+ * Parse version 3.0 ACL
+ ************************************************************
+ */
+
+start_acl_v3: acl_list
+ ;
+
+acl_list: acl
+ | acl_list acl
+ ;
+
+acl: named_acl ';' body_list
+ | named_acl ';'
+ ;
+
+named_acl: ACL_ACL_TOK ACL_VARIABLE_TOK
+ {
+ curr_acl = ACL_AclNew(NULL, $<string>2);
+ free($<string>2);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ yyerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ }
+ | ACL_ACL_TOK ACL_QSTRING_TOK
+ {
+ curr_acl = ACL_AclNew(NULL, $<string>2);
+ free($<string>2);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ yyerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ }
+ ;
+
+body_list: body
+ | body body_list
+ ;
+
+body: authenticate_statement ';'
+ | authorization_statement ';'
+ | deny_statement ';'
+ ;
+
+deny_statement:
+ ACL_ABSOLUTE_TOK ACL_DENY_TOK ACL_WITH_TOK
+ {
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_RESPONSE) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(deny) failed");
+ return(-1);
+ }
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ if ( ACL_ExprSetPFlags(NULL, curr_expr,
+ ACL_PFLAG_ABSOLUTE) < 0 ) {
+ yyerror("Could not set deny processing flags");
+ return(-1);
+ }
+ }
+ deny_common
+ | ACL_DENY_TOK ACL_WITH_TOK
+ {
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_RESPONSE) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(deny) failed");
+ return(-1);
+ }
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ }
+ deny_common
+ ;
+
+deny_common: ACL_VARIABLE_TOK ACL_EQ_TOK ACL_QSTRING_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( ACL_ExprSetDenyWith(NULL, curr_expr,
+ $<string>1, $<string>3) < 0 ) {
+ yyerror("ACL_ExprSetDenyWith() failed");
+ return(-1);
+ }
+ free($<string>1);
+ free($<string>3);
+ }
+ ;
+
+authenticate_statement: ACL_AUTHENTICATE_TOK
+ {
+ pflags = 0;
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_AUTH) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ curr_auth_info = PListCreate(NULL, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ if ( ACL_ExprAddAuthInfo(curr_expr, curr_auth_info) < 0 ) {
+ yyerror("Could not set authorization info");
+ return(-1);
+ }
+ }
+ '(' attribute_list ')' '{' parameter_list '}'
+ {
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ }
+ ;
+
+attribute_list: attribute
+ | attribute_list ',' attribute
+
+attribute: ACL_VARIABLE_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( ACL_ExprAddArg(NULL, curr_expr, $<string>1) < 0 ) {
+ yyerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+ free($<string>1);
+ }
+ ;
+
+parameter_list: parameter ';'
+ | parameter ';' parameter_list
+ ;
+
+parameter: ACL_VARIABLE_TOK ACL_EQ_TOK ACL_QSTRING_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index($<string>1), $<string>1, $<string>3, NULL) < 0 ) {
+ }
+ free($<string>1);
+ }
+ | ACL_VARIABLE_TOK ACL_EQ_TOK ACL_VARIABLE_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index($<string>1), $<string>1, $<string>3, NULL) < 0 ) {
+ }
+ free($<string>1);
+ }
+ ;
+
+authorization_statement: ACL_ALLOW_TOK
+ {
+ pflags = 0;
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_ALLOW) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ }
+ auth_common_action
+ | ACL_DENY_TOK
+ {
+ pflags = 0;
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_DENY) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(deny) failed");
+ return(-1);
+ }
+ }
+ auth_common_action
+ ;
+
+auth_common_action:
+ {
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ }
+ auth_common
+ {
+ if ( ACL_ExprSetPFlags (NULL, curr_expr, pflags) < 0 ) {
+ yyerror("Could not set authorization processing flags");
+ return(-1);
+ }
+#ifdef DEBUG
+ if ( ACL_ExprDisplay(curr_expr) < 0 ) {
+ yyerror("ACL_ExprDisplay() failed");
+ return(-1);
+ }
+ printf("Parsed authorization.\n");
+#endif
+ }
+ ;
+
+auth_common: flag_list '(' args_list ')' expression
+ ;
+
+flag_list:
+ | ACL_ABSOLUTE_TOK
+ {
+ pflags = ACL_PFLAG_ABSOLUTE;
+ }
+ | ACL_ABSOLUTE_TOK content_static
+ {
+ pflags = ACL_PFLAG_ABSOLUTE;
+ }
+ | ACL_CONTENT_TOK
+ {
+ pflags = ACL_PFLAG_CONTENT;
+ }
+ | ACL_CONTENT_TOK absolute_static
+ {
+ pflags = ACL_PFLAG_CONTENT;
+ }
+ | ACL_TERMINAL_TOK
+ {
+ pflags = ACL_PFLAG_TERMINAL;
+ }
+ | ACL_TERMINAL_TOK content_absolute
+ {
+ pflags = ACL_PFLAG_TERMINAL;
+ }
+ ;
+
+content_absolute: ACL_CONTENT_TOK
+ {
+ pflags |= ACL_PFLAG_CONTENT;
+ }
+ | ACL_ABSOLUTE_TOK
+ {
+ pflags |= ACL_PFLAG_ABSOLUTE;
+ }
+ | ACL_CONTENT_TOK ACL_ABSOLUTE_TOK
+ {
+ pflags |= ACL_PFLAG_ABSOLUTE | ACL_PFLAG_CONTENT;
+ }
+ | ACL_ABSOLUTE_TOK ACL_CONTENT_TOK
+ {
+ pflags |= ACL_PFLAG_ABSOLUTE | ACL_PFLAG_CONTENT;
+ }
+ ;
+
+content_static: ACL_CONTENT_TOK
+ {
+ pflags |= ACL_PFLAG_CONTENT;
+ }
+ | ACL_TERMINAL_TOK
+ {
+ pflags |= ACL_PFLAG_TERMINAL;
+ }
+ | ACL_CONTENT_TOK ACL_TERMINAL_TOK
+ {
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_CONTENT;
+ }
+ | ACL_TERMINAL_TOK ACL_CONTENT_TOK
+ {
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_CONTENT;
+ }
+ ;
+
+absolute_static: ACL_ABSOLUTE_TOK
+ {
+ pflags |= ACL_PFLAG_ABSOLUTE;
+ }
+ | ACL_TERMINAL_TOK
+ {
+ pflags |= ACL_PFLAG_TERMINAL;
+ }
+ | ACL_ABSOLUTE_TOK ACL_TERMINAL_TOK
+ {
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_ABSOLUTE;
+ }
+ | ACL_TERMINAL_TOK ACL_ABSOLUTE_TOK
+ {
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_ABSOLUTE;
+ }
+ ;
+
+args_list: arg
+ | args_list ',' arg
+ ;
+
+arg: ACL_VARIABLE_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( ACL_ExprAddArg(NULL, curr_expr, $<string>1) < 0 ) {
+ yyerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+ free( $<string>1 );
+ }
+ ;
+
+expression: factor
+ | factor ACL_AND_TOK expression
+ {
+ if ( ACL_ExprAnd(NULL, curr_expr) < 0 ) {
+ yyerror("ACL_ExprAnd() failed");
+ return(-1);
+ }
+ }
+ | factor ACL_OR_TOK expression
+ {
+ if ( ACL_ExprOr(NULL, curr_expr) < 0 ) {
+ yyerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+ ;
+
+factor: base_expr
+ | '(' expression ')'
+ | ACL_NOT_TOK factor
+ {
+ if ( ACL_ExprNot(NULL, curr_expr) < 0 ) {
+ yyerror("ACL_ExprNot() failed");
+ return(-1);
+ }
+ }
+ ;
+
+base_expr: ACL_VARIABLE_TOK relop ACL_QSTRING_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( ACL_ExprTerm(NULL, curr_expr,
+ $<string>1, (CmpOp_t) $<ival>2, $<string>3) < 0 ) {
+ yyerror("ACL_ExprTerm() failed");
+ free($<string>1);
+ free($<string>3);
+ return(-1);
+ }
+ free($<string>1);
+ free($<string>3);
+ }
+ | ACL_VARIABLE_TOK relop ACL_VARIABLE_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( ACL_ExprTerm(NULL, curr_expr,
+ $<string>1, (CmpOp_t) $<ival>2, $<string>3) < 0 ) {
+ yyerror("ACL_ExprTerm() failed");
+ free($<string>1);
+ free($<string>3);
+ return(-1);
+ }
+ free($<string>1);
+ free($<string>3);
+ }
+ ;
+
+relop: ACL_EQ_TOK
+ | ACL_GE_TOK
+ | ACL_GT_TOK
+ | ACL_LT_TOK
+ | ACL_LE_TOK
+ | ACL_NE_TOK
+ ;
+%%
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;
+}
diff --git a/lib/libaccess/aclutil.cpp b/lib/libaccess/aclutil.cpp
new file mode 100644
index 00000000..8d30fffb
--- /dev/null
+++ b/lib/libaccess/aclutil.cpp
@@ -0,0 +1,223 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Source file for the TimeOfDay and DayOfWeek LAS drivers
+ */
+
+#include <netsite.h>
+#include <base/crit.h>
+/* #include <plhash.h> */
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/las.h>
+#include <libaccess/nserror.h>
+#include "aclutil.h"
+
+/* Generic evaluator of comparison operators in attribute evaluation
+ * statements.
+ * INPUT
+ * CmpOp_t ACL_TOKEN_EQ, ACL_TOKEN_NE etc.
+ * result 0 if equal, >0 if real > pattern, <0 if
+ * real < pattern.
+ * RETURNS
+ * LAS_EVAL_TRUE or LAS_EVAL_FALSE or LAS_EVAL_INVALID
+ * DEBUG
+ * Can add asserts that the strcmp failure cases are one of the
+ * remaining legal comparators.
+ */
+int
+evalComparator(CmpOp_t ctok, int result)
+{
+ if (result == 0) {
+ switch(ctok) {
+ case CMP_OP_EQ:
+ case CMP_OP_GE:
+ case CMP_OP_LE:
+ return LAS_EVAL_TRUE;
+ case CMP_OP_NE:
+ case CMP_OP_GT:
+ case CMP_OP_LT:
+ return LAS_EVAL_FALSE;
+ default:
+ return LAS_EVAL_INVALID;
+ }
+ } else if (result > 0) {
+ switch(ctok) {
+ case CMP_OP_GT:
+ case CMP_OP_GE:
+ case CMP_OP_NE:
+ return LAS_EVAL_TRUE;
+ case CMP_OP_LT:
+ case CMP_OP_LE:
+ case CMP_OP_EQ:
+ return LAS_EVAL_FALSE;
+ default:
+ return LAS_EVAL_INVALID;
+ }
+ } else { /* real < pattern */
+ switch(ctok) {
+ case CMP_OP_LT:
+ case CMP_OP_LE:
+ case CMP_OP_NE:
+ return LAS_EVAL_TRUE;
+ case CMP_OP_GT:
+ case CMP_OP_GE:
+ case CMP_OP_EQ:
+ return LAS_EVAL_FALSE;
+ default:
+ return LAS_EVAL_INVALID;
+ }
+ }
+}
+
+
+/* Takes a string and returns the same string with all uppercase
+* letters converted to lowercase.
+*/
+void
+makelower(char *string)
+{
+ while (*string) {
+ *string = tolower(*string);
+ string++;
+ }
+}
+
+
+/* Given an LAS_EVAL_* value, translates to ACL_RES_* */
+int
+EvalToRes(int value)
+{
+ switch (value) {
+ case LAS_EVAL_TRUE:
+ return ACL_RES_ALLOW;
+ case LAS_EVAL_FALSE:
+ return ACL_RES_DENY;
+ case LAS_EVAL_DECLINE:
+ return ACL_RES_FAIL;
+ case LAS_EVAL_FAIL:
+ return ACL_RES_FAIL;
+ case LAS_EVAL_INVALID:
+ return ACL_RES_INVALID;
+ case LAS_EVAL_NEED_MORE_INFO:
+ return ACL_RES_DENY;
+ default:
+ NS_ASSERT(1);
+ return ACL_RES_ERROR;
+ }
+}
+
+const char *comparator_string (int comparator)
+{
+ static char invalid_cmp[32];
+
+ switch(comparator) {
+ case CMP_OP_EQ: return "CMP_OP_EQ";
+ case CMP_OP_NE: return "CMP_OP_NE";
+ case CMP_OP_GT: return "CMP_OP_GT";
+ case CMP_OP_LT: return "CMP_OP_LT";
+ case CMP_OP_GE: return "CMP_OP_GE";
+ case CMP_OP_LE: return "CMP_OP_LE";
+ default:
+ sprintf(invalid_cmp, "unknown comparator %d", comparator);
+ return invalid_cmp;
+ }
+}
+
+/* Return the pointer to the next token after replacing the following 'delim'
+ * char with NULL.
+ * WARNING - Modifies the first parameter */
+char *acl_next_token (char **ptr, char delim)
+{
+ char *str = *ptr;
+ char *token = str;
+ char *comma;
+
+ if (!token) { *ptr = 0; return 0; }
+
+ /* ignore leading whitespace */
+ while(*token && isspace(*token)) token++;
+
+ if (!*token) { *ptr = 0; return 0; }
+
+ if ((comma = strchr(token, delim)) != NULL) {
+ *comma++ = 0;
+ }
+
+ {
+ /* ignore trailing whitespace */
+ int len = strlen(token);
+ char *sptr = token+len-1;
+
+ while(*sptr == ' ' || *sptr == '\t') *sptr-- = 0;
+ }
+
+ *ptr = comma;
+ return token;
+}
+
+
+/* Returns a pointer to the next token and it's length */
+/* tokens are separated by 'delim' characters */
+/* ignores whitespace surrounding the tokens */
+const char *acl_next_token_len (const char *ptr, char delim, int *len)
+{
+ const char *str = ptr;
+ const char *token = str;
+ const char *comma;
+
+ *len = 0;
+
+ if (!token) { return 0; }
+
+ /* ignore leading whitespace */
+ while(*token && isspace(*token)) token++;
+
+ if (!*token) { return 0; }
+ if (*token == delim) { return token; } /* str starts with delim! */
+
+ if ((comma = strchr(token, delim)) != NULL) {
+ *len = comma - token;
+ }
+ else {
+ *len = strlen(token);
+ }
+
+ {
+ /* ignore trailing whitespace */
+ const char *sptr = token + *len - 1;
+
+ while(*sptr == ' ' || *sptr == '\t') {
+ sptr--;
+ (*len)--;
+ }
+ }
+
+ return token;
+}
+
+/* acl_get_req_time --
+ * If the REQ_TIME is available on the 'resource' plist, return it.
+ * Otherwise, make a system call to get the time and insert the time on the
+ * 'resource' PList. Allocate the time_t structure using the 'resource'
+ * PList's pool.
+ */
+time_t *acl_get_req_time (PList_t resource)
+{
+ time_t *req_time = 0;
+ int rv = PListGetValue(resource, ACL_ATTR_TIME_INDEX, (void **)&req_time,
+ NULL);
+
+ if (rv < 0) {
+ req_time = (time_t *)pool_malloc(PListGetPool(resource), sizeof(time_t));
+ time(req_time);
+ PListInitProp(resource, ACL_ATTR_TIME_INDEX, ACL_ATTR_TIME,
+ (void *)req_time, NULL);
+ }
+
+ return req_time;
+}
diff --git a/lib/libaccess/aclutil.h b/lib/libaccess/aclutil.h
new file mode 100644
index 00000000..34a1d0a6
--- /dev/null
+++ b/lib/libaccess/aclutil.h
@@ -0,0 +1,25 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef ACLUTIL_H
+#define ACLUTIL_H
+
+NSPR_BEGIN_EXTERN_C
+
+int evalComparator(CmpOp_t ctok, int result);
+void makelower(char *string);
+int EvalToRes(int value);
+const char *comparator_string (int comparator);
+
+/*Warning: acl_next_token modifies 'ptr' */
+char *acl_next_token (char **ptr, char delim);
+
+const char *acl_next_token_len (const char *ptr,
+ char delim, int *len);
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/attrec.cpp b/lib/libaccess/attrec.cpp
new file mode 100644
index 00000000..8911e896
--- /dev/null
+++ b/lib/libaccess/attrec.cpp
@@ -0,0 +1,309 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (attrec.c)
+ *
+ * This module contains routines for encoding and decoding
+ * attribute records. See attrec.h for a description of attribute
+ * records.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "assert.h"
+#define __PRIVATE_ATTREC
+#include "libaccess/attrec.h"
+
+/*
+ * Description (NTS_Length)
+ *
+ * This function returns the length of a null-terminated string.
+ * The length includes the terminating null octet.
+ *
+ * Use of the NTSLENGTH() macro is recommended (see attrec.h).
+ *
+ * Arguments:
+ *
+ * nts - a pointer to the null-terminate string
+ * (may be null)
+ *
+ * Returns:
+ *
+ * The length of the string. If 'nts' is null, the value is one,
+ * since there is always a null octet.
+ */
+
+int NTS_Length(NTS_t nts)
+{
+ return ((nts) ? strlen((const char *)nts) + 1 : 1);
+}
+
+/*
+ * Description (NTS_Decode)
+ *
+ * This function decodes a null-terminated string from a specified
+ * attribute record buffer. It copies the string into a dynamically
+ * allocated buffer, if 'pnts' is not null, and returns a pointer
+ * to it. The return value of the function is a pointer to the
+ * octet following the NTS in the attribute record buffer.
+ *
+ * Use of the NTSDECODE() macro is recommended (see attrec.h).
+ *
+ * Arguments:
+ *
+ * cp - pointer into the attribute record buffer
+ * pnts - pointer to returned reference to decoded
+ * NTS, or null, if the decoded NTS is not
+ * to be copied to a dynamic buffer
+ *
+ * Returns:
+ *
+ * The function return value is a pointer to the octet following
+ * the NTS in the attribute record buffer. A pointer to a
+ * dynamically allocated buffer containing the decoded NTS will
+ * be returned through 'pnts', if it is non-null. This returned
+ * pointer will be null if the NTS contains only a terminating
+ * octet.
+ */
+
+ATR_t NTS_Decode(ATR_t cp, NTS_t * pnts)
+{
+ NTS_t nts = 0;
+ int len = NTSLENGTH(cp); /* length of the string */
+
+ /* Are we going to return a copy of the string? */
+ if (pnts) {
+
+ /* Yes, is it more than just a null octet? */
+ if (len > 1) {
+
+ /* Yes, allocate a buffer and copy the string to it */
+ nts = (NTS_t)MALLOC(len);
+ if (nts) {
+ memcpy((void *)nts, (void *)cp, len);
+ }
+ }
+
+ /* Return a pointer to the copied string, or null */
+ *pnts = nts;
+ }
+
+ /* Return pointer to octet after string */
+ return cp + len;
+}
+
+/*
+ * Description (NTS_Encode)
+ *
+ * This function encodes a null-terminated string into a specified
+ * attribute record buffer. It returns a pointer to the octet
+ * following the encoding.
+ *
+ * Use of the NTSENCODE() macro is recommended (see attrec.h).
+ *
+ * Arguments:
+ *
+ * cp - pointer into the attribute record buffer
+ * nts - pointer to the string to be encoded
+ *
+ * Returns:
+ *
+ * A pointer to the octet following the encoding in the attribute
+ * record buffer is returned.
+ */
+
+ATR_t NTS_Encode(ATR_t cp, NTS_t nts)
+{
+
+ /* Is the string pointer null? */
+ if (nts) {
+ int len = NTSLENGTH(nts);
+
+ /* No, copy the string to the attribute record buffer */
+ memcpy((void *)cp, (void *)nts, len);
+
+ /* Get pointer to octet after it */
+ cp += len;
+ }
+ else {
+
+ /* A null pointer indicates an empty NTS, i.e. just a null octet */
+ *cp++ = 0;
+ }
+
+ /* Return a pointer to the octet after the encoding */
+ return cp;
+}
+
+/*
+ * Description (USI_Decode)
+ *
+ * This function decodes an unsigned integer value from a specified
+ * attribute record buffer.
+ *
+ * Use of the USIDECODE() macro is recommended (see attrec.h).
+ *
+ * Arguments:
+ *
+ * cp - pointer into the attribute record buffer
+ * pval - pointer to returned integer value
+ *
+ * Returns:
+ *
+ * If 'pval' is not null, the decoded integer value is returned
+ * in the referenced location. The function return value is a
+ * pointer to the octet following the USI encoding in the attribute
+ * record buffer.
+ */
+
+ATR_t USI_Decode(ATR_t cp, USI_t * pval)
+{
+ int val;
+
+ /* Is this a length value? */
+ if (*(cp) & 0x80) {
+ int i;
+ int len;
+
+ /* Yes, build the value from the indicated number of octets */
+ len = *cp++ & 0x7;
+ val = 0;
+ for (i = 0; i < len; ++i) {
+ val <<= 8;
+ val |= (cp[i] & 0xff);
+ }
+ cp += len;
+ }
+ else {
+
+ /* This octet is the value */
+ val = *cp++;
+ }
+
+ /* Return the value if there's a place to put it */
+ if (pval) *pval = val;
+
+ /* Return a pointer to the next item in the attribute record */
+ return cp;
+}
+
+/*
+ * Description (USI_Encode)
+ *
+ * This function encodes an unsigned integer value into a specified
+ * attribute record buffer.
+ *
+ * Use of the USIENCODE() macro is recommended (see attrec.h).
+ *
+ * Arguments:
+ *
+ * cp - pointer into the attribute record buffer
+ * val - the value to be encoded
+ *
+ * Returns:
+ *
+ * A pointer to the octet following the generated encoding in the
+ * attribute record buffer is returned.
+ */
+
+ATR_t USI_Encode(ATR_t cp, USI_t val)
+{
+ /* Check size of value to be encoded */
+ if (val <= 0x7f) *cp++ = val;
+ else if (val <= 0xff) {
+ /* Length plus 8-bit value */
+ *cp++ = 0x81;
+ *cp++ = val;
+ }
+ else if (val <= 0xffff) {
+ /* Length plus 16-bit value */
+ *cp++ = 0x82;
+ cp[1] = val & 0xff;
+ val >>= 8;
+ cp[0] = val & 0xff;
+ cp += 2;
+ }
+ else if (val <= 0xffffff) {
+ /* Length plus 24-bit value */
+ *cp++ = 0x83;
+ cp[2] = val & 0xff;
+ val >>= 8;
+ cp[1] = val & 0xff;
+ val >>= 8;
+ cp[0] = val & 0xff;
+ cp += 3;
+ }
+ else {
+ /* Length plus 32-bit value */
+ *cp++ = 0x84;
+ cp[3] = val & 0xff;
+ val >>= 8;
+ cp[2] = val & 0xff;
+ val >>= 8;
+ cp[1] = val & 0xff;
+ val >>= 8;
+ cp[0] = val & 0xff;
+ cp += 4;
+ }
+
+ /* Return a pointer to the next position in the attribute record */
+ return cp;
+}
+
+/*
+ * Description (USI_Insert)
+ *
+ * This function is a variation of USI_Encode() that always generates
+ * the maximum-length encoding for USI value, regardless of the
+ * actual specified value. For arguments, returns, see USI_Encode().
+ *
+ * Use of the USIINSERT() macro is recommended. The USIALLOC() macro
+ * returns the number of octets that USIINSERT() will generate.
+ */
+
+ATR_t USI_Insert(ATR_t cp, USI_t val)
+{
+ int i;
+
+ assert(USIALLOC() == 5);
+
+ *cp++ = 0x84;
+ for (i = 3; i >= 0; --i) {
+ cp[i] = val & 0xff;
+ val >>= 8;
+ }
+
+ return cp + 5;
+}
+
+/*
+ * Description (USI_Length)
+ *
+ * This function returns the number of octets required to encode
+ * an unsigned integer value.
+ *
+ * Use of the USILENGTH() macro is recommended (see attrec.h).
+ *
+ * Arguments:
+ *
+ * val - the unsigned integer value
+ *
+ * Returns:
+ *
+ * The number of octets required to encode the specified value is
+ * returned.
+ */
+
+int USI_Length(USI_t val)
+{
+ return (((USI_t)(val) <= 0x7f) ? 1
+ : (((USI_t)(val) <= 0xff) ? 2
+ : (((USI_t)(val) <= 0xffff) ? 3
+ : (((USI_t)(val) <= 0xffffff) ? 4
+ : 5))));
+}
+
diff --git a/lib/libaccess/authdb.cpp b/lib/libaccess/authdb.cpp
new file mode 100644
index 00000000..0d27635d
--- /dev/null
+++ b/lib/libaccess/authdb.cpp
@@ -0,0 +1,339 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <stdio.h>
+#include <string.h>
+
+#include <plhash.h>
+
+#include <netsite.h>
+#include "permhash.h"
+#include <ldaputil/errors.h>
+#include <ldaputil/certmap.h>
+#include <ldaputil/dbconf.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/authdb.h>
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include <libaccess/acl.h>
+#include <libaccess/aclglobal.h>
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+
+#define BIG_LINE 1024
+
+char *ACL_default_dbname = 0;
+ACLDbType_t ACL_default_dbtype = ACL_DBTYPE_INVALID;
+ACLMethod_t ACL_default_method = ACL_METHOD_INVALID;
+int acl_registered_dbcnt = 0;
+
+extern int acl_registered_names(PLHashTable *ht, int count, char ***names);
+
+/************************** Database Types *************************/
+
+#define databaseNamesHashTable ACLDbNameHash
+
+int acl_num_databases ()
+{
+ return acl_registered_dbcnt;
+}
+
+static int reg_dbname_internal (NSErr_t *errp, ACLDbType_t dbtype,
+ const char *dbname, const char *url,
+ PList_t plist)
+{
+ DbParseFn_t parseFunc;
+ void *db;
+ int rv;
+ AuthdbInfo_t *authdb_info;
+
+ if (!ACL_DbTypeIsRegistered(errp, dbtype)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4400, ACL_Program, 2, XP_GetAdminStr(DBT_DbtypeNotDefinedYet), dbname);
+ return -1;
+ }
+
+ parseFunc = ACL_DbTypeParseFn(errp, dbtype);
+
+ if (!parseFunc) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4400, ACL_Program, 2, XP_GetAdminStr(DBT_DbtypeNotDefinedYet), dbname);
+ return -1;
+ }
+
+ rv = (*parseFunc)(errp, dbtype, dbname, url, plist, (void **)&db);
+
+ if (rv < 0) {
+ /* plist contains error message/code */
+ return rv;
+ }
+
+ /* Store the db returned by the parse function in the hash table.
+ */
+
+ authdb_info = (AuthdbInfo_t *)pool_malloc(ACL_DATABASE_POOL, sizeof(AuthdbInfo_t));
+
+ if (!authdb_info) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4420, ACL_Program, 0);
+ return -1;
+ }
+
+ authdb_info->dbname = pool_strdup(ACL_DATABASE_POOL, dbname);
+ authdb_info->dbtype = dbtype;
+ authdb_info->dbinfo = db; /* value returned from parseFunc */
+
+ PR_HashTableAdd(ACLDbNameHash, authdb_info->dbname, authdb_info);
+ acl_registered_dbcnt++;
+
+ return 0;
+}
+
+NSAPI_PUBLIC int ACL_DatabaseRegister (NSErr_t *errp, ACLDbType_t dbtype,
+ const char *dbname, const char *url,
+ PList_t plist)
+{
+ if (!dbname || !*dbname) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4500, ACL_Program, 1, XP_GetAdminStr(DBT_DatabaseRegisterDatabaseNameMissing));
+ return -1;
+ }
+
+ return reg_dbname_internal(errp, dbtype, dbname, url, plist);
+}
+
+NSAPI_PUBLIC int
+ACL_DatabaseNamesGet(NSErr_t *errp, char ***names, int *count)
+{
+ *count = acl_registered_dbcnt;
+ return acl_registered_names (ACLDbNameHash, *count, names);
+}
+
+NSAPI_PUBLIC int
+ACL_DatabaseNamesFree(NSErr_t *errp, char **names, int count)
+{
+ int i;
+
+ for (i = count-1; i; i--) FREE(names[i]);
+
+ FREE(names);
+ return 0;
+}
+
+/* try to determine the dbtype from the database url */
+static int acl_url_to_dbtype (const char *url, ACLDbType_t *dbtype_out)
+{
+ ACLDbType_t dbtype;
+ NSErr_t *errp = 0;
+
+ *dbtype_out = dbtype = ACL_DBTYPE_INVALID;
+ if (!url || !*url) return -1;
+
+ // urls with ldap:, ldaps: and ldapdb: are all of type ACL_DBTYPE_LDAP.
+ if (!strncmp(url, URL_PREFIX_LDAP, URL_PREFIX_LDAP_LEN))
+ dbtype = ACL_DbTypeLdap;
+ else {
+ /* treat prefix in the url as dbtype if it has been registered.
+ */
+ int prefix_len = strcspn(url, ":");
+ char dbtypestr[BIG_LINE];
+
+ if (prefix_len) {
+ strncpy(dbtypestr, url, prefix_len);
+ dbtypestr[prefix_len] = 0;
+
+ if (!ACL_DbTypeFind(errp, dbtypestr, &dbtype)) {
+ /* prefix is not a registered dbtype */
+ dbtype = ACL_DBTYPE_INVALID;
+ }
+ }
+ }
+
+ if (ACL_DbTypeIsEqual(errp, dbtype, ACL_DBTYPE_INVALID)) {
+ /* try all the registered parse functions to determine the dbtype */
+ }
+
+ if (ACL_DbTypeIsEqual(errp, dbtype, ACL_DBTYPE_INVALID)) return -1;
+
+ *dbtype_out = dbtype;
+ return 0;
+}
+
+NSAPI_PUBLIC int ACL_RegisterDbFromACL (NSErr_t *errp, const char *url,
+ ACLDbType_t *dbtype)
+{
+ /* If the database by name url is already registered, don't do anything.
+ * If it is not registered, determine the dbtype from the url.
+ * If the dbtype can be determined, register the database with dbname same
+ * as the url. Return the dbtype.
+ */
+ void *db;
+ int rv;
+ PList_t plist;
+
+ if (ACL_DatabaseFind(errp, url, dbtype, &db) == LAS_EVAL_TRUE)
+ return 0;
+
+ /* The database is not registered yet. Parse the url to find out its
+ * type. If parsing fails, return failure.
+ */
+ rv = acl_url_to_dbtype(url, dbtype);
+
+ if (rv < 0) {
+ return rv;
+ }
+
+ plist = PListNew(NULL);
+ rv = ACL_DatabaseRegister(errp, *dbtype, url, url, plist);
+ PListDestroy(plist);
+ return rv;
+}
+
+NSAPI_PUBLIC int ACL_DatabaseFind(NSErr_t *errp, const char *name,
+ ACLDbType_t *dbtype, void **db)
+{
+ AuthdbInfo_t *info;
+
+ *dbtype = ACL_DBTYPE_INVALID;
+ *db = 0;
+
+ if (ACLDbNameHash) {
+ info = (AuthdbInfo_t *)PR_HashTableLookup(ACLDbNameHash,
+#ifdef NSPR20
+ name
+#else
+ (char *)name
+#endif
+ );
+
+ if (info) {
+ *dbtype = info->dbtype;
+ *db = info->dbinfo;
+
+ return LAS_EVAL_TRUE;
+ }
+ }
+
+ return LAS_EVAL_FAIL;
+}
+
+
+NSAPI_PUBLIC int ACL_ReadDbMapFile (NSErr_t *errp, const char *map_file,
+ int default_only)
+{
+ DBConfInfo_t *info;
+ DBConfDBInfo_t *db_info;
+ DBPropVal_t *propval;
+ PList_t plist;
+ int rv;
+ int seen_default = 0;
+
+ if (default_only)
+ rv = dbconf_read_default_dbinfo(map_file, &db_info);
+ else
+ rv = dbconf_read_config_file(map_file, &info);
+
+ if (rv != LDAPU_SUCCESS) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4600, ACL_Program, 3, XP_GetAdminStr(DBT_ReadDbMapFileErrorReadingFile), map_file, ldapu_err2string(rv));
+ return -1;
+ }
+
+ rv = 0;
+
+ if (!default_only)
+ db_info = info->firstdb;
+
+ while(db_info) {
+ char *url = db_info->url;
+ char *dbname = db_info->dbname;
+ ACLDbType_t dbtype;
+
+ /* process db_info */
+ if (url) {
+ rv = acl_url_to_dbtype(url, &dbtype);
+
+ if (rv < 0) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4610, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ReadDbMapFileCouldntDetermineDbtype), url);
+ break;
+ }
+ }
+ else {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4620, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ReadDbMapFileMissingUrl), dbname);
+ rv = -1;
+ break;
+ }
+
+ /* convert any property-value pairs in db_info into plist */
+ plist = PListNew(NULL);
+ propval = db_info->firstprop;
+
+ while(propval) {
+ if (propval->prop) {
+ PListInitProp(plist, 0, propval->prop, propval->val, 0);
+ }
+ else {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4630, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ReadDbMapFileInvalidPropertyPair), dbname);
+ rv = -1;
+ break;
+ }
+ propval = propval->next;
+ }
+
+ if (rv < 0) break;
+
+ /* register the database */
+ rv = ACL_DatabaseRegister(errp, dbtype, dbname, url, plist);
+ PListDestroy(plist);
+
+ if (rv < 0) {
+ /* Failed to register database */
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4640, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ReadDbMapFileRegisterDatabaseFailed), dbname);
+ break;
+ }
+
+ /* If the dbname is "default", set the default_dbtype */
+ if (!strcmp(dbname, DBCONF_DEFAULT_DBNAME)) {
+ if (!ACL_DbTypeIsEqual(errp, dbtype, ACL_DbTypeLdap)) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4350, ACL_Program, 1,
+ XP_GetAdminStr(DBT_ReadDbMapFileDefaultDatabaseNotLdap));
+ rv = -1;
+ break;
+ }
+ if (seen_default) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4360, ACL_Program, 1, XP_GetAdminStr(DBT_ReadDbMapFileMultipleDefaultDatabases));
+ rv = -1;
+ break;
+ }
+ seen_default = 1;
+ ACL_DatabaseSetDefault(errp, dbname);
+ }
+
+ db_info = db_info->next;
+ }
+
+ if (!seen_default) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4370, ACL_Program, 1, XP_GetAdminStr(DBT_ReadDbMapFileMissingDefaultDatabase));
+ rv = -1;
+ }
+
+ if (default_only)
+ dbconf_free_dbinfo(db_info);
+ else
+ dbconf_free_confinfo(info);
+
+ return rv;
+}
+
+void
+ACL_DatabaseDestroy(void)
+{
+ pool_destroy(ACL_DATABASE_POOL);
+ ACL_DATABASE_POOL = NULL;
+ ACLDbNameHash = NULL;
+ return;
+}
+
diff --git a/lib/libaccess/avadb.c b/lib/libaccess/avadb.c
new file mode 100644
index 00000000..c0d98704
--- /dev/null
+++ b/lib/libaccess/avadb.c
@@ -0,0 +1,300 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libaccess/ava.h"
+#include "libaccess/avadb.h"
+#include "base/session.h"
+#include "base/pblock.h"
+#include "frame/req.h"
+#include "frame/log.h"
+
+#include "libadmin/libadmin.h"
+#include "libaccess/avapfile.h"
+
+#define DB_NAME "AvaMap"
+
+enum {AVA_DB_SUCCESS=0,AVA_DB_FAILURE};
+
+#ifdef XP_UNIX
+#include "mcom_ndbm.h"
+
+USE_NSAPI int AddEntry (char *key, char *value) {
+ datum keyd;
+ datum valued;
+ DBM *db = NULL;
+ char dbpath[150];
+
+ sprintf (dbpath, "%s%c%s", get_httpacl_dir(), FILE_PATHSEP, DB_NAME);
+
+ db = dbm_open (dbpath, O_RDWR | O_CREAT, 0644);
+
+ if (!db)
+ return AVA_DB_FAILURE;
+
+ keyd.dptr = key;
+ keyd.dsize = strlen (key) + 1;
+
+ valued.dptr = value;
+ valued.dsize = strlen(value) + 1;
+
+ dbm_store (db, keyd, valued, DBM_REPLACE);
+ dbm_close (db);
+
+ return AVA_DB_SUCCESS;
+}
+
+USE_NSAPI int DeleteEntry (char *key) {
+ datum keyd;
+ DBM *db = NULL;
+ char dbpath[150];
+
+ sprintf (dbpath, "%s%c%s", get_httpacl_dir(), FILE_PATHSEP, DB_NAME);
+
+ db = dbm_open (dbpath, O_RDWR, 0644);
+
+ if (!db)
+ return AVA_DB_FAILURE;
+
+ keyd.dptr = key;
+ keyd.dsize = strlen (key) + 1;
+
+ dbm_delete (db, keyd);
+
+ dbm_close (db);
+
+ return AVA_DB_SUCCESS;
+}
+
+USE_NSAPI char *GetValue (char *key) {
+ datum keyd;
+ datum valued;
+ DBM *db = NULL;
+ char dbpath[150];
+
+ sprintf (dbpath, "%s%c%s", get_httpacl_dir(), FILE_PATHSEP, DB_NAME);
+
+ db = dbm_open (dbpath, O_RDONLY, 0644);
+
+ if (!db)
+ return NULL;
+
+ keyd.dptr = key;
+ keyd.dsize = strlen (key) + 1;
+
+ valued = dbm_fetch (db, keyd);
+
+ dbm_close (db);
+
+ return valued.dptr;
+}
+
+#else
+
+#include <stdio.h>
+
+
+#define lmemcpy memcpy
+#define lmemcmp memcmp
+#define lmemset memset
+
+static int mkhash8(char *x,int len) {
+ unsigned int i,hash = 0;
+ for (i=0; i < len; i++) { hash += x[i]; }
+
+ return (int) (hash & 0xff);
+}
+
+static void mkpath(char *target, char *dir, char sep, char *name) {
+ int len;
+
+ len = strlen(dir);
+ lmemcpy(target,dir,len);
+ target += len;
+
+ *target++ = sep;
+
+ len = strlen(name);
+ lmemcpy(target,name,len);
+ target += len;
+
+ *target = 0;
+}
+
+#define DELETED_LEN 8
+static char DELETED[] = { 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff , 0x0 };
+
+
+#define RECORD_SIZE 512
+USE_NSAPI int AddEntry (char *key, char *value) {
+ int empty, hash;
+ char dbpath[150];
+ char record[RECORD_SIZE];
+ int key_len, val_len,size;
+ FILE *f;
+
+ mkpath (dbpath, get_httpacl_dir(), FILE_PATHSEP, DB_NAME);
+
+ f = fopen(dbpath, "rb+");
+ if (f == NULL) {
+ f = fopen(dbpath,"wb+");
+ }
+
+ if (f == NULL)
+ return AVA_DB_FAILURE;
+
+ key_len = strlen(key)+1;
+ val_len = strlen(value);
+
+ if ((key_len+val_len) > RECORD_SIZE) {
+ fclose(f);
+ return AVA_DB_FAILURE;
+ }
+
+
+ /* now hash the key */
+ hash = mkhash8(key,key_len);
+ empty = -1;
+
+ fseek(f,hash*RECORD_SIZE,SEEK_SET);
+
+ for (;;) {
+ size= fread(record,1,RECORD_SIZE,f);
+ if (size < RECORD_SIZE) {
+ break;
+ }
+ if (lmemcmp(record,key,key_len) == 0) {
+ break;
+ }
+ if ((empty == -1) && (lmemcmp(record,DELETED,DELETED_LEN) == 0)) {
+ empty = hash;
+ }
+ if (record == 0) {
+ break;
+ }
+ hash++;
+ }
+
+ if (empty != -1) { hash = empty; }
+ fseek(f,hash*RECORD_SIZE,SEEK_SET);
+
+ /* build the record */
+ lmemset(record,0,RECORD_SIZE);
+
+ lmemcpy(record,key,key_len);
+ lmemcpy(&record[key_len],value,val_len);
+ size= fwrite(record,1,RECORD_SIZE,f);
+ if (size != RECORD_SIZE) {
+ fclose(f);
+ return AVA_DB_FAILURE;
+ }
+ fclose(f);
+
+ return AVA_DB_SUCCESS;
+}
+
+USE_NSAPI int DeleteEntry (char *key) {
+ int found,hash;
+ char dbpath[150];
+ char record[RECORD_SIZE];
+ int key_len,size;
+ FILE *f;
+
+ mkpath (dbpath, get_httpacl_dir(), FILE_PATHSEP, DB_NAME);
+
+ f = fopen(dbpath, "rb+");
+
+ if (f == NULL)
+ return AVA_DB_FAILURE;
+
+ key_len = strlen(key)+1;
+
+
+ /* now hash the key */
+ hash = mkhash8(key,key_len);
+ found = 0;
+ fseek(f,hash*RECORD_SIZE,SEEK_SET);
+
+ for (;;) {
+ size= fread(record,1,RECORD_SIZE,f);
+ if (size < RECORD_SIZE) {
+ break;
+ }
+ if (lmemcmp(record,key,key_len) == 0) {
+ found++;
+ break;
+ }
+ if (record == 0) {
+ break;
+ }
+ hash++;
+ }
+
+ if (!found) {
+ fclose(f);
+ return AVA_DB_SUCCESS;
+ }
+ fseek(f,hash*RECORD_SIZE,SEEK_SET);
+
+ /* build the record */
+ lmemset(record,0,RECORD_SIZE);
+
+ lmemcpy(record,DELETED,DELETED_LEN);
+ size= fwrite(record,1,RECORD_SIZE,f);
+ if (size != RECORD_SIZE) {
+ fclose(f);
+ return AVA_DB_FAILURE;
+ }
+ fclose(f);
+
+ return AVA_DB_SUCCESS;
+}
+
+USE_NSAPI char *GetValue (char *key) {
+ int hash,size;
+ char dbpath[150];
+ char record[RECORD_SIZE];
+ int key_len,found = 0;
+ FILE *f;
+
+ mkpath (dbpath, get_httpacl_dir(), FILE_PATHSEP, DB_NAME);
+
+ f = fopen(dbpath, "rb");
+
+ if (f == NULL)
+ return NULL;
+
+ key_len = strlen(key)+1;
+
+ /* now hash the key */
+ hash = mkhash8(key,key_len);
+
+ fseek(f,hash*RECORD_SIZE,SEEK_SET);
+
+ for(;;) {
+ size= fread(record,1,RECORD_SIZE,f);
+ if (size < RECORD_SIZE) {
+ break;
+ }
+ if (lmemcmp(record,key,key_len) == 0) {
+ found++;
+ break;
+ }
+ if (record == 0) {
+ break;
+ }
+ hash++;
+ }
+
+ fclose(f);
+ if (!found) return NULL;
+
+ return system_strdup(&record[key_len+1]);
+}
+
+#endif
diff --git a/lib/libaccess/avaparse.y b/lib/libaccess/avaparse.y
new file mode 100644
index 00000000..c28ef165
--- /dev/null
+++ b/lib/libaccess/avaparse.y
@@ -0,0 +1,140 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+%{
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "libaccess/ava.h"
+#include "libaccess/avapfile.h"
+#include "netsite.h"
+
+extern int linenum;
+extern char yytext[];
+
+static void AddDefType (int defType, char *defId);
+static void AddAVA (char* userID);
+
+void yyerror(const char* string);
+extern void logerror(const char* string,int num, char *file);
+
+AVAEntry tempEntry;
+AVATable entryTable;
+
+%}
+
+%union {
+ char *string;
+ int num;
+}
+
+%token DEF_C DEF_CO DEF_OU DEF_CN EQ_SIGN DEF_START
+%token DEF_L DEF_E DEF_ST
+%token <string> USER_ID DEF_ID
+
+%type <num> def.type
+
+%start source
+
+%%
+
+source: ava.database
+ |
+ ;
+
+
+ava.database: ava.database ava
+ | ava
+ ;
+
+ava: USER_ID definitions {AddAVA($1);};
+
+definitions: definition.list
+ |
+ ;
+
+definition.list: definition.list definition
+ | definition
+ ;
+
+
+definition: def.type EQ_SIGN DEF_ID {AddDefType($1, $3);};
+
+def.type: DEF_C {$$ = DEF_C; }
+ | DEF_CO {$$ = DEF_CO;}
+ | DEF_OU {$$ = DEF_OU;}
+ | DEF_CN {$$ = DEF_CN;}
+ | DEF_L {$$ = DEF_L; }
+ | DEF_E {$$ = DEF_E; }
+ | DEF_ST {$$ = DEF_ST;}
+ ;
+
+%%
+
+void yyerror(const char* string) {
+ logerror(string,linenum,currFile);
+}
+
+
+void AddDefType (int defType, char *defId) {
+ switch (defType) {
+ case DEF_C:
+ tempEntry.country = defId;
+ break;
+ case DEF_CO:
+ tempEntry.company = defId;
+ break;
+ case DEF_OU:
+ if (tempEntry.numOrgs % ORGS_ALLOCSIZE == 0) {
+ if (tempEntry.numOrgs == 0) {
+ tempEntry.organizations =
+ PERM_MALLOC (sizeof (char*) * ORGS_ALLOCSIZE);
+ } else {
+ char **temp;
+ temp =
+ PERM_MALLOC(sizeof(char*) * (tempEntry.numOrgs + ORGS_ALLOCSIZE));
+ memcpy (temp, tempEntry.organizations,
+ sizeof(char*)*tempEntry.numOrgs);
+ PERM_FREE (tempEntry.organizations);
+ tempEntry.organizations = temp;
+ }
+ }
+ tempEntry.organizations[tempEntry.numOrgs++] = defId;
+ break;
+ case DEF_CN:
+ tempEntry.CNEntry = defId;
+ break;
+ case DEF_E:
+ tempEntry.email = defId;
+ break;
+ case DEF_L:
+ tempEntry.locality = defId;
+ break;
+ case DEF_ST:
+ tempEntry.state = defId;
+ break;
+ default:
+ break;
+ }
+}
+
+void AddAVA (char* userID) {
+ AVAEntry *newAVA;
+
+ newAVA = (AVAEntry*)PERM_MALLOC(sizeof(AVAEntry));
+ if (!newAVA) {
+ yyerror ("Out of Memory in AddAVA");
+ return;
+ }
+ *newAVA = tempEntry;
+ newAVA->userid = userID;
+
+ _addAVAtoTable (newAVA, &entryTable);
+
+ tempEntry.CNEntry = tempEntry.userid = tempEntry.country = tempEntry.company = 0;
+ tempEntry.email = tempEntry.locality = tempEntry.state = NULL;
+ tempEntry.numOrgs = 0;
+}
diff --git a/lib/libaccess/avapfile.c b/lib/libaccess/avapfile.c
new file mode 100644
index 00000000..8c955d9d
--- /dev/null
+++ b/lib/libaccess/avapfile.c
@@ -0,0 +1,428 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libaccess/ava.h"
+
+#include "base/session.h"
+#include "base/pblock.h"
+#include "frame/req.h"
+#include "frame/log.h"
+
+#include "libadmin/libadmin.h"
+#include "libaccess/avapfile.h"
+
+#define ALLOC_SIZE 20
+#define SUCCESS 0
+
+struct parsedStruct {
+ char *fileName;
+ AVATable *avaTable;
+};
+
+typedef struct parsedStruct Parsed;
+
+/* globals for yy_error if needed */
+Session *yy_sn = NULL;
+Request *yy_rq = NULL;
+
+/*This will be a dynamic array of parsedStruct*. Re-sizing if necessary.*/
+struct ParsedTable {
+ Parsed **parsedTable;
+ int numEntries;
+};
+
+char *currFile;
+
+static struct ParsedTable parsedFiles = {NULL, 0};
+
+extern AVATable entryTable; /*Table where entries are stored*/
+extern AVAEntry tempEntry; /*Used to restore parser's state*/
+extern linenum;
+
+AVAEntry * AVAEntry_Dup(AVAEntry *entry) {
+ int i;
+ AVAEntry *newAVA = NULL;
+/* copy the AVA entry */
+
+ if (entry) {
+ newAVA = (AVAEntry *) PERM_MALLOC(sizeof(AVAEntry));
+ memset(newAVA,0, sizeof(AVAEntry));
+ newAVA->userid = 0;
+ newAVA->CNEntry = 0;
+ newAVA->email = 0;
+ newAVA->locality = 0;
+ newAVA->state = 0;
+ newAVA->country = 0;
+ newAVA->company = 0;
+ newAVA->organizations = 0;
+ newAVA->numOrgs = 0;
+ if (entry->userid) newAVA->userid = PERM_STRDUP(entry->userid);
+ if (entry->CNEntry) newAVA->CNEntry = PERM_STRDUP(entry->CNEntry);
+ if (entry->email) newAVA->email = PERM_STRDUP(entry->email);
+ if (entry->locality) newAVA->locality = PERM_STRDUP(entry->locality);
+ if (entry->state) newAVA->state = PERM_STRDUP(entry->state);
+ if (entry->country) newAVA->country = PERM_STRDUP(entry->country);
+ if (entry->company) newAVA->company = PERM_STRDUP(entry->company);
+ if (entry->organizations) {
+ newAVA->organizations = PERM_MALLOC(sizeof(char *)*entry->numOrgs);
+ newAVA->numOrgs = entry->numOrgs;
+ for (i=0; i<entry->numOrgs; i++)
+ newAVA->organizations[i] = PERM_STRDUP (entry->organizations[i]);
+ }
+ }
+ return newAVA;
+}
+
+void _addAVAtoTable (AVAEntry *newAVA, AVATable *table) {
+ int i;
+ int insertIndex = -1;
+
+ if (table->numEntries%ENTRIES_ALLOCSIZE == 0) {
+ if (table->numEntries == 0) {
+ table->enteredTable =
+ (AVAEntry**) PERM_MALLOC (sizeof(AVAEntry*) * ENTRIES_ALLOCSIZE);
+ } else {
+ AVAEntry **temp;
+
+ temp =
+ PERM_MALLOC(sizeof(AVAEntry*)*(table->numEntries+ENTRIES_ALLOCSIZE));
+ memmove(temp, table->enteredTable, sizeof(AVAEntry*)*table->numEntries);
+ PERM_FREE(table->enteredTable);
+ table->enteredTable = temp;
+ }
+ }
+
+ for (i=table->numEntries-1; i >= 0; i--) {
+ if (strcmp(newAVA->userid, table->enteredTable[i]->userid) > 0) {
+ insertIndex = i+1;
+ break;
+ } else {
+ table->enteredTable[i+1] = table->enteredTable[i];
+ }
+ }
+
+
+ table->enteredTable[(insertIndex == -1) ? 0 : insertIndex] = newAVA;
+ (table->numEntries)++;
+}
+
+AVATable *AVATableDup(AVATable *table) {
+ AVATable *newTable = (AVATable*)PERM_MALLOC (sizeof(AVATable));
+ /* round the puppy so _addAVAtoTable still works */
+ int size = (table->numEntries + (ENTRIES_ALLOCSIZE-1))/ENTRIES_ALLOCSIZE;
+ int i;
+
+ newTable->enteredTable =
+ (AVAEntry**)PERM_MALLOC(size*ENTRIES_ALLOCSIZE*sizeof(AVAEntry *));
+
+ for (i=0; i < table->numEntries; i++) {
+ newTable->enteredTable[i] = AVAEntry_Dup(table->enteredTable[i]);
+ }
+ newTable->numEntries = table->numEntries;
+ return newTable;
+}
+
+
+
+
+AVAEntry *_getAVAEntry(char *groupName, AVATable *mapTable) {
+ char line[BIG_LINE];
+ int lh, rh, mid, cmp;;
+
+ if (!mapTable) {
+ sprintf (line, "NULL Pointer passed as mapTable when trying to get entry %s", groupName);
+ report_error (SYSTEM_ERROR, "File Not Found", line);
+ }
+
+
+ lh = 0;
+ rh = mapTable->numEntries-1;
+
+ while (lh <= rh) {
+ mid = lh + ((rh-lh)/2);
+ cmp = strcmp(groupName, mapTable->enteredTable[mid]->userid);
+ if (cmp == 0)
+ return mapTable->enteredTable[mid];
+ else if (cmp > 0)
+ lh = mid + 1;
+ else
+ rh = mid - 1;
+ }
+
+ return NULL;
+
+}
+
+AVATable *_getTable (char *fileName) {
+ int lh, rh, mid, cmp;
+ AVATable *table = NULL;
+
+ /*First checks to see if it's already been parsed*/
+
+ lh = 0;
+ rh = parsedFiles.numEntries-1;
+ while (lh <= rh) {
+ mid = lh + ((rh - lh)/2);
+ cmp = strcmp(fileName, parsedFiles.parsedTable[mid]->fileName);
+ if (cmp == SUCCESS) {
+ return parsedFiles.parsedTable[mid]->avaTable;
+ } else if (cmp < SUCCESS) {
+ rh = mid-1;
+ } else {
+ lh = mid+1;
+ }
+ }
+
+ yyin = fopen (fileName, "r");
+
+ if (yyin) {
+ if (!yyparse()) {
+ table = _wasParsed (fileName);
+ table->userdb = NULL;
+ }
+ fclose (yyin);
+ }
+
+ return table;
+}
+
+int _hasBeenParsed (char *aclFileName){
+ return (_getTable(aclFileName) != NULL);
+}
+
+AVATable* _wasParsed (char *inFileName) {
+ Parsed *newEntry;
+ int i;
+
+ if (!inFileName)
+ return NULL;
+
+ newEntry = (Parsed*) PERM_MALLOC (sizeof(Parsed));
+ newEntry->fileName = PERM_STRDUP (inFileName);
+ newEntry->avaTable = AVATableDup(&entryTable);
+
+ if (parsedFiles.numEntries % ALLOC_SIZE == 0) {
+ if (parsedFiles.numEntries) {
+ Parsed **temp;
+
+ temp = PERM_MALLOC (sizeof(Parsed*)*(parsedFiles.numEntries + ALLOC_SIZE));
+ if (!temp)
+ return NULL;
+ memcpy (temp, parsedFiles.parsedTable, sizeof(Parsed*)*parsedFiles.numEntries);
+ PERM_FREE (parsedFiles.parsedTable);
+ parsedFiles.parsedTable = temp;
+ } else {
+ parsedFiles.parsedTable =
+ (Parsed**) PERM_MALLOC (sizeof (Parsed*) * ALLOC_SIZE);
+ if (!parsedFiles.parsedTable)
+ return NULL;
+ }
+ }
+ for (i=parsedFiles.numEntries; i > 0; i--) {
+ if (strcmp(newEntry->fileName,parsedFiles.parsedTable[i-1]->fileName) < 0) {
+ parsedFiles.parsedTable[i] = parsedFiles.parsedTable[i-1];
+ } else {
+ break;
+ }
+ }
+ parsedFiles.parsedTable[i] = newEntry;
+ parsedFiles.numEntries++;
+
+/*Initialize parser structures to resemble that before parse*/
+ entryTable.numEntries = 0;
+ tempEntry.country = tempEntry.company = tempEntry.CNEntry = NULL;
+ tempEntry.email = tempEntry.locality = tempEntry.state = NULL;
+ linenum = 1;
+
+ return newEntry->avaTable;
+}
+
+AVAEntry *_deleteAVAEntry (char *group, AVATable *table) {
+ int removeIndex;
+ int lh, rh, mid, cmp;
+ AVAEntry *entry = NULL;
+
+ if (!group || !table)
+ return NULL;
+
+ lh = 0;
+ rh = table->numEntries - 1;
+
+ while (lh <= rh) {
+ mid = lh + ((rh-lh)/2);
+ cmp = strcmp (group, table->enteredTable[mid]->userid);
+ if (cmp == SUCCESS) {
+ removeIndex = mid;
+ break;
+ } else if (cmp < SUCCESS) {
+ rh = mid-1;
+ } else {
+ lh = mid+1;
+ }
+ }
+
+ if (lh > rh)
+ return NULL;
+
+ entry = table->enteredTable[removeIndex];
+
+ memmove ((char*)(table->enteredTable)+(sizeof(AVAEntry*)*removeIndex),
+ (char*)(table->enteredTable)+(sizeof(AVAEntry*)*(removeIndex+1)),
+ (table->numEntries - removeIndex - 1)*sizeof(AVAEntry*));
+
+ (table->numEntries)--;
+
+ return entry;
+}
+
+void AVAEntry_Free (AVAEntry *entry) {
+ int i;
+
+ if (entry) {
+ if (entry->userid)
+ PERM_FREE (entry->userid);
+ if (entry->CNEntry)
+ PERM_FREE (entry->CNEntry);
+ if (entry->email)
+ PERM_FREE (entry->email);
+ if (entry->locality)
+ PERM_FREE (entry->locality);
+ if (entry->state)
+ PERM_FREE (entry->state);
+ if (entry->country)
+ PERM_FREE (entry->country);
+ if (entry->company)
+ PERM_FREE (entry->company);
+ if (entry->organizations) {
+ for (i=0; i<entry->numOrgs; i++)
+ PERM_FREE (entry->organizations[i]);
+ PERM_FREE(entry->organizations);
+ }
+ }
+}
+
+void PrintHeader(FILE *outfile){
+
+ fprintf (outfile,"/*This file is generated automatically by the admin server\n");
+ fprintf (outfile," *Any changes you make manually may be lost if other\n");
+ fprintf (outfile," *changes are made through the admin server.\n");
+ fprintf (outfile," */\n\n\n");
+
+}
+
+void writeOutEntry (FILE *outfile, AVAEntry *entry) {
+ int i;
+
+ /*What should I do if the group id is not there?*/
+ if (!entry || !(entry->userid))
+ report_error (SYSTEM_ERROR, "AVA-DB Failure",
+ "Bad entry passed to write out function");
+
+ fprintf (outfile,"%s: {\n", entry->userid);
+ if (entry->CNEntry)
+ fprintf (outfile,"\tCN=\"%s\"\n", entry->CNEntry);
+ if (entry->email)
+ fprintf (outfile,"\tE=\"%s\"\n", entry->email);
+ if (entry->company)
+ fprintf (outfile,"\tO=\"%s\"\n", entry->company);
+ if (entry->organizations) {
+ for (i=0; i < entry->numOrgs; i++) {
+ fprintf (outfile, "\tOU=\"%s\"\n", entry->organizations[i]);
+ }
+ }
+ if (entry->locality)
+ fprintf (outfile,"\tL=\"%s\"\n",entry->locality);
+ if (entry->state)
+ fprintf (outfile,"\tST=\"%s\"\n",entry->state);
+ if (entry->country)
+ fprintf (outfile,"\tC=\"%s\"\n", entry->country);
+
+ fprintf (outfile,"}\n\n\n");
+
+}
+
+void writeOutFile (char *authdb, AVATable *table) {
+ char line[BIG_LINE];
+ char mess[200];
+ FILE *newfile;
+ int i;
+
+ sprintf (line, "%s%c%s%c%s.%s", get_authdb_dir(), FILE_PATHSEP, authdb, FILE_PATHSEP,
+ AUTH_DB_FILE, AVADB_TAG);
+
+ if (!table) {
+ sprintf (mess, "The structure for file %s was not loaded before writing out", line);
+ report_error (SYSTEM_ERROR, "Internal Error", mess);
+ }
+
+ newfile = fopen (line, "w");
+
+ if (!newfile) {
+ sprintf (mess, "Could not open file %s for writing.", line);
+ report_error(FILE_ERROR, "No File", mess);
+ }
+
+ PrintHeader (newfile);
+
+ for (i=0;i < table->numEntries; i++) {
+ writeOutEntry (newfile, table->enteredTable[i]);
+ }
+
+ fclose(newfile);
+}
+
+
+void
+logerror(char *error,int line,char *file) {
+ /* paranoia */
+ /*ava-mapping is only functin that initializes yy_sn and yy_rq*/
+ if ((yy_sn != NULL) && (yy_rq != NULL)) {
+ log_error (LOG_FAILURE, "ava-mapping", yy_sn, yy_rq,
+ "Parse error line %d of %s: %s", line, file, error);
+ } else {
+ char errMess[250];
+
+ sprintf (errMess, "Parse error line %d of %s: %s", line, file, error);
+ report_error (SYSTEM_ERROR, "Failure: Loading AVA-DB Table", errMess);
+ }
+}
+
+
+void outputAVAdbs(char *chosen) {
+ char *authdbdir = get_authdb_dir();
+ char **listings;
+ int i;
+ int numListings = 0;
+ int hasOptions = 0;
+
+ listings = list_auth_dbs(authdbdir);
+
+ while (listings[numListings++] != NULL);
+
+ for (i=0; listings[i] != NULL ; i++) {
+ if (!hasOptions) {
+ printf ("<select name=\"%s\"%s onChange=\"form.submit()\">",AVA_DB_SEL,
+ (numListings > SELECT_OVERFLOW)?"size=5":"");
+ hasOptions = 1;
+ }
+
+ printf ("<option value=\"%s\"%s>%s\n",listings[i],
+ (strcmp(chosen, listings[i]) == 0) ? "SELECTED":"",listings[i]);
+ }
+
+ if (hasOptions)
+ printf ("</select>\n");
+ else
+ printf ("<i><b>Insert an AVA-Database entry first</b></i>\n");/*This should never happen,
+ *since I never create an empty
+ *avadb file,
+ *but one never knows
+ */
+
+}
diff --git a/lib/libaccess/avascan.l b/lib/libaccess/avascan.l
new file mode 100644
index 00000000..ceae1426
--- /dev/null
+++ b/lib/libaccess/avascan.l
@@ -0,0 +1,106 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+%{
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include "y.tab.h"
+#include "libaccess/ava.h"
+#include "netsite.h"
+
+int linenum = 1;
+int first_time = 1;
+int old_state;
+int num_nested_comments = 0;
+
+extern AVAEntry tempEntry;
+extern AVATable entryTable;
+
+void strip_quotes(void);
+
+%}
+
+%s COMMENT NORM DEFINES DEF_TYPE
+
+uc_letter [A-Z]
+lc_letter [a-z]
+digit [0-9]
+under_score _
+
+letter ([A-Z,a-z])
+
+white_space ([ \t]*)
+identifier ([_,A-Z,a-z][_,A-Z,a-z,0-9]*)
+def_identifier (({white_space}{identifier})+)
+text (\"[^\"]*\")
+comments (([^"*/"\n])*)
+
+
+
+%%
+
+%{
+ if (first_time) {
+ BEGIN NORM;
+ first_time = tempEntry.numOrgs = 0;
+ old_state = NORM;
+ tempEntry.userid = 0;
+ tempEntry.country = 0;
+ tempEntry.CNEntry = 0;
+ tempEntry.email = 0;
+ tempEntry.locality = 0;
+ tempEntry.state = 0;
+ entryTable.numEntries = 0;
+ }
+%}
+
+
+"/*" {BEGIN COMMENT; num_nested_comments++;}
+<COMMENT>"*/" {num_nested_comments--;
+ if (!num_nested_comments) BEGIN old_state;}
+<COMMENT>. {;}
+
+<NORM>{identifier} {yylval.string = PERM_STRDUP(yytext);
+ return USER_ID;}
+<NORM>":"{white_space}\{ {BEGIN DEF_TYPE;
+ old_state = DEF_TYPE;}
+
+<DEF_TYPE>"C" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_C; }
+<DEF_TYPE>"O" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_CO;}
+<DEF_TYPE>"OU" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_OU;}
+<DEF_TYPE>"CN" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_CN;}
+<DEF_TYPE>"L" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_L;}
+<DEF_TYPE>"E" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_E;}
+<DEF_TYPE>"ST" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_ST;}
+<DEF_TYPE>"}" {BEGIN NORM;old_state = NORM;}
+
+<DEFINES>= {return EQ_SIGN;}
+<DEFINES>{text} {BEGIN DEF_TYPE; old_state = DEF_TYPE;
+ strip_quotes();
+ return DEF_ID;}
+
+{white_space} {;}
+\n {linenum++;}
+. {yyerror("Bad input character");}
+%%
+
+int yywrap () {
+ return 1;
+}
+
+void strip_quotes(void) {
+ yytext[strlen(yytext)-1]= '\0';
+ yylval.string = PERM_STRDUP(&yytext[1]);
+}
diff --git a/lib/libaccess/las.h b/lib/libaccess/las.h
new file mode 100644
index 00000000..3dfdf1e9
--- /dev/null
+++ b/lib/libaccess/las.h
@@ -0,0 +1,53 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef LAS_H
+#define LAS_H
+
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include <base/plist.h>
+
+NSPR_BEGIN_EXTERN_C
+
+extern int LASTimeOfDayEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASDayOfWeekEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASIpEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASDnsEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASGroupEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASUserEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+/* MLM - for admin delegation */
+extern int LASProgramEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+extern void LASTimeOfDayFlush(void **cookie);
+extern void LASDayOfWeekFlush(void **cookie);
+extern void LASIpFlush(void **cookie);
+extern void LASDnsFlush(void **cookie);
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/lasdns.cpp b/lib/libaccess/lasdns.cpp
new file mode 100644
index 00000000..22a37dac
--- /dev/null
+++ b/lib/libaccess/lasdns.cpp
@@ -0,0 +1,373 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* lasdns.c
+ * This file contains the DNS LAS code.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef XP_WIN32
+/* #include <winsock2.h> */
+#include <winsock.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
+#include <netsite.h>
+extern "C" {
+#include <prnetdb.h>
+}
+#include <base/plist.h>
+#include <base/pool.h>
+#include <libaccess/nserror.h>
+#include <libaccess/nsauth.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include "lasdns.h"
+#include "aclutil.h"
+#include "aclcache.h"
+#include "permhash.h"
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+#include "access_plhash.h"
+extern "C" {
+#include <nspr.h>
+}
+
+#ifdef UTEST
+extern int LASDnsGetDns(char **dnsv);
+#endif
+
+/* LASDnsMatch
+ * Given an array of fully-qualified dns names, tries to match them
+ * against a given hash table.
+ * INPUT
+ * dns DNS string
+ * context pointer to an LAS DNS context structure
+ *
+ * In our usage, this context is derived from
+ * an acllist cache, which is a representation of
+ * of some global acis--in other words it's a global thing
+ * shared between threads--hence the use
+ * of the "read-only" hash lookup routines here.
+ */
+int
+LASDnsMatch(char *token, LASDnsContext_t *context)
+{
+
+ /* Test for the unusual case where "*" is allowed */
+ if (ACL_HashTableLookup_const(context->Table, "*"))
+ return LAS_EVAL_TRUE;
+
+ /* Start with the full name. Then strip off each component
+ * leaving the remainder starting with a period. E.g.
+ * splash.mcom.com
+ * .mcom.com
+ * .com
+ * Search the hash table for each remaining portion. Remember that
+ * wildcards were put in with the leading period intact.
+ */
+ do {
+ if (ACL_HashTableLookup_const(context->Table, token))
+ return LAS_EVAL_TRUE;
+
+ token = strchr(&token[1], '.');
+ } while (token != NULL);
+
+ return LAS_EVAL_FALSE;
+
+}
+
+/* LASDNSBuild
+ * Builds a hash table of all the hostnames provided (plus their aliases
+ * if aliasflg is true). Wildcards are only permitted in the leftmost
+ * field. They're represented in the hash table by a leading period.
+ * E.g. ".mcom.com".
+ *
+ * RETURNS Zero on success, else LAS_EVAL_INVALID
+ */
+int
+LASDnsBuild(NSErr_t *errp, char *attr_pattern, LASDnsContext_t *context, int aliasflg)
+{
+ int delimiter; /* length of valid token */
+ char token[256]; /* max length dns name */
+ int i;
+ int ipcnt;
+ char **p;
+ unsigned long *ipaddrs=0;
+ pool_handle_t *pool;
+ PRStatus error=PR_SUCCESS;
+ char buffer[PR_NETDB_BUF_SIZE];
+#ifdef UTEST
+ struct hostent *he, host;
+#else
+ PRHostEnt *he, host;
+#endif
+
+ context->Table = PR_NewHashTable(0,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ pool = pool_create();
+ context->pool = pool;
+ if ((!context->Table) || (!context->pool)) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4700, ACL_Program, 1,
+ XP_GetAdminStr(DBT_lasdnsbuildUnableToAllocateHashT_));
+ return LAS_EVAL_INVALID;
+ }
+
+ do {
+ /* Get a single hostname from the pattern string */
+ delimiter = strcspn(attr_pattern, ", \t");
+ strncpy(token, attr_pattern, delimiter);
+ token[delimiter] = '\0';
+
+ /* Skip any white space after the token */
+ attr_pattern += delimiter;
+ attr_pattern += strspn(attr_pattern, ", \t");
+
+ /* If there's a wildcard, strip it off but leave the "."
+ * Can't have aliases for a wildcard pattern.
+ * Treat "*" as a special case. If so, go ahead and hash it.
+ */
+ if (token[0] == '*') {
+ if (token[1] != '\0') {
+ if (!PR_HashTableAdd(context->Table, pool_strdup(pool, &token[1]), (void *)-1)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4710, ACL_Program, 2,
+ XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), token);
+ return LAS_EVAL_INVALID;
+ }
+ } else {
+ if (!PR_HashTableAdd(context->Table, pool_strdup(pool, token), (void *)-1)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4720, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), token);
+ return LAS_EVAL_INVALID;
+ }
+ }
+ } else {
+ /* This is a single hostname add it to the hash table */
+ if (!PR_HashTableAdd(context->Table, pool_strdup(pool, &token[0]), (void *)-1)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4730, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), token);
+ return LAS_EVAL_INVALID;
+ }
+
+ if (aliasflg) {
+ /* memset(buffer, '\0', PR_NETDB_BUF_SIZE);
+ */
+#ifdef UTEST
+ he = gethostbyname(token);
+#else
+ error = PR_GetHostByName(token,
+ buffer,
+ PR_NETDB_BUF_SIZE,
+ &host);
+ if (error == PR_SUCCESS) he = &host;
+ else he = NULL;
+#endif
+ if (he) {
+ /* Make a copy of the list of IP addresses if any */
+ if (he->h_addr_list && he->h_addr_list[0]) {
+
+ /* Count the IP addresses */
+ for (p = he->h_addr_list, ipcnt = 0; *p; ++p) {
+ ++ipcnt;
+ }
+
+ /* Allocate space */
+ ipaddrs = (unsigned long *)PERM_MALLOC(ipcnt * sizeof(unsigned long));
+
+ /* Copy IP addresses */
+ for (i = 0; i < ipcnt; ++i) {
+ ipaddrs[i] = 0;
+ memcpy((void *)&ipaddrs[i], he->h_addr_list[i], 4);
+ }
+ }
+
+ /* Add each of the aliases to the list */
+ if (he->h_aliases && he->h_aliases[0]) {
+
+ for (p = he->h_aliases; *p; ++p) {
+ /* Add it to the hash table */
+ if (!PR_HashTableAdd(context->Table, pool_strdup(pool, *p), (void*)-1)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4740, ACL_Program, 2,
+ XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), *p);
+ PERM_FREE(ipaddrs);
+ return LAS_EVAL_INVALID;
+ }
+ }
+ }
+
+ for (i = 0; i < ipcnt; ++i) {
+
+#ifdef UTEST
+ he = gethostbyaddr((char *)&ipaddrs[i], 4, AF_INET);
+#else
+ error = PR_GetHostByAddr((PRNetAddr *)&ipaddrs[i],
+ buffer,
+ PR_NETDB_BUF_SIZE,
+ &host);
+ if (error == PR_SUCCESS) he = &host;
+ else he = NULL;
+#endif
+ if (he) {
+ if (he->h_name) {
+ /* Add it to the hash table */
+ if (!PR_HashTableAdd(context->Table, pool_strdup(pool, he->h_name),
+ (void *)-1)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4750, ACL_Program, 2,
+ XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), he->h_name);
+ PERM_FREE(ipaddrs);
+ return LAS_EVAL_INVALID;
+ }
+ }
+
+ if (he->h_aliases && he->h_aliases[0]) {
+ for (p = he->h_aliases; *p; ++p) {
+ /* Add it to the hash table */
+ if (!PR_HashTableAdd(context->Table, pool_strdup(pool, *p), (void *)-1)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4760, ACL_Program, 2,
+ XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), *p);
+ PERM_FREE(ipaddrs);
+ return LAS_EVAL_INVALID;
+ }
+ }
+ }
+ }
+ }
+
+ PERM_FREE(ipaddrs);
+
+ } /* if he */
+
+
+ } /* if aliasflg */
+
+ } /* else - single hostname */
+
+
+ } while ((attr_pattern != NULL) &&
+ (attr_pattern[0] != '\0') &&
+ (delimiter != (int)NULL));
+
+ return 0;
+}
+
+/* LASDnsFlush
+ * Given the address of a las_cookie for a DNS expression entry, frees up
+ * all allocated memory for it. This includes the hash table, plus the
+ * context structure.
+ */
+void
+LASDnsFlush(void **las_cookie)
+{
+ if (*las_cookie == NULL)
+ return;
+
+ pool_destroy(((LASDnsContext_t *)*las_cookie)->pool);
+ PR_HashTableDestroy(((LASDnsContext_t *)*las_cookie)->Table);
+ PERM_FREE(*las_cookie);
+ *las_cookie = NULL;
+ return;
+}
+
+/*
+ * LASDnsEval
+ * INPUT
+ * attr_name The string "dns" - in lower case.
+ * comparator CMP_OP_EQ or CMP_OP_NE only
+ * attr_pattern A comma-separated list of DNS names
+ * Any segment(s) in a DNS name can be wildcarded using
+ * "*". Note that this is not a true Regular Expression
+ * form.
+ * *cachable Always set to ACL_INDEF_CACHE
+ * subject Subject property list
+ * resource Resource property list
+ * auth_info Authentication info, if any
+ * RETURNS
+ * ret code The usual LAS return codes.
+ */
+int LASDnsEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, ACLCachable_t *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth)
+{
+ int result;
+ int aliasflg;
+ char *my_dns;
+ LASDnsContext_t *context;
+ int rv;
+
+ *cachable = ACL_INDEF_CACHABLE;
+
+ if (strcmp(attr_name, "dns") == 0)
+ aliasflg = 0;
+ else if (strcmp(attr_name, "dnsalias") == 0)
+ aliasflg = 1;
+ else {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4800, ACL_Program, 2, XP_GetAdminStr(DBT_lasDnsBuildReceivedRequestForAtt_), attr_name);
+ return LAS_EVAL_INVALID;
+ }
+
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4810, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsevalIllegalComparatorDN_), comparator_string(comparator));
+ return LAS_EVAL_INVALID;
+ }
+
+ /* If this is the first time through, build the pattern tree first. */
+ if (*LAS_cookie == NULL) {
+ ACL_CritEnter();
+ if (*LAS_cookie == NULL) { /* Must check again */
+ *LAS_cookie = context =
+ (LASDnsContext_t *)PERM_MALLOC(sizeof(LASDnsContext_t));
+ if (context == NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4820, ACL_Program, 1, XP_GetAdminStr(DBT_lasdnsevalUnableToAllocateContex_));
+ ACL_CritExit();
+ return LAS_EVAL_FAIL;
+ }
+ context->Table = NULL;
+ LASDnsBuild(errp, attr_pattern, context, aliasflg);
+ }
+ ACL_CritExit();
+ } else
+ context = (LASDnsContext *) *LAS_cookie;
+
+ /* Call the DNS attribute getter */
+#ifdef UTEST
+ LASDnsGetDns(&my_dns); /* gets stuffed on return */
+#else
+ rv = ACL_GetAttribute(errp, ACL_ATTR_DNS, (void **)&my_dns,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ if (subject || resource) {
+ char rv_str[16];
+ /* Don't ereport if called from ACL_CachableAclList */
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4830, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsevalUnableToGetDnsErrorDN_), rv_str);
+ }
+ return LAS_EVAL_FAIL;
+ }
+#endif
+
+ result = LASDnsMatch(my_dns, context);
+
+ if (comparator == CMP_OP_NE) {
+ if (result == LAS_EVAL_FALSE)
+ return LAS_EVAL_TRUE;
+ else if (result == LAS_EVAL_TRUE)
+ return LAS_EVAL_FALSE;
+ }
+ return (result);
+}
diff --git a/lib/libaccess/lasdns.h b/lib/libaccess/lasdns.h
new file mode 100644
index 00000000..3d86dc98
--- /dev/null
+++ b/lib/libaccess/lasdns.h
@@ -0,0 +1,10 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+typedef struct LASDnsContext {
+ PRHashTable *Table;
+ pool_handle_t *pool;
+} LASDnsContext_t;
diff --git a/lib/libaccess/lasgroup.cpp b/lib/libaccess/lasgroup.cpp
new file mode 100644
index 00000000..6ff5d1bb
--- /dev/null
+++ b/lib/libaccess/lasgroup.cpp
@@ -0,0 +1,164 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* #define DBG_PRINT */
+
+/* lasgroup.c
+ * This file contains the Group LAS code.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <netsite.h>
+#include "aclpriv.h"
+#include <libaccess/usrcache.h>
+#include <libaccess/las.h>
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+#include <ldaputil/errors.h> /* for DBG_PRINT */
+#include "aclutil.h"
+
+#ifdef UTEST
+extern char *LASGroupGetUser();
+#endif /* UTEST */
+
+
+/*
+ * LASGroupEval
+ * INPUT
+ * attr_name The string "group" - in lower case.
+ * comparator CMP_OP_EQ or CMP_OP_NE only
+ * attr_pattern A comma-separated list of groups
+ * *cachable Always set to ACL_NOT_CACHABLE
+ * subject Subjust property list
+ * resource Resource property list
+ * auth_info Authentication info, if any
+ * RETURNS
+ * retcode The usual LAS return codes.
+ */
+int LASGroupEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, ACLCachable_t *cachable,
+ void **LAS_cookie, PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth)
+{
+ char *groups = attr_pattern;
+ int retcode;
+ char *member_of;
+ char *user;
+ char *dbname;
+ time_t *req_time = 0;
+ const char *group;
+ char delim;
+ int len;
+ int rv;
+
+ *cachable = ACL_NOT_CACHABLE;
+ *LAS_cookie = (void *)0;
+
+ if (strcmp(attr_name, ACL_ATTR_GROUP) != 0) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4900, ACL_Program, 2, XP_GetAdminStr(DBT_lasGroupEvalReceivedRequestForAt_), attr_name);
+ return LAS_EVAL_INVALID;
+ }
+
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4910, ACL_Program, 2, XP_GetAdminStr(DBT_lasgroupevalIllegalComparatorDN_), comparator_string(comparator));
+ return LAS_EVAL_INVALID;
+ }
+
+ if (!strcmp(attr_pattern, "anyone")) {
+ *cachable = ACL_INDEF_CACHABLE;
+ return comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+ }
+
+ /* Get the authenticated user */
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USER, (void **)&user,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return rv;
+ }
+
+ rv = ACL_AuthInfoGetDbname(auth_info, &dbname);
+
+ if (rv < 0) {
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4920, ACL_Program, 2, XP_GetAdminStr(DBT_lasGroupEvalUnableToGetDatabaseName), rv_str);
+ return LAS_EVAL_FAIL;
+ }
+
+ rv = LAS_EVAL_FALSE;
+
+ if (acl_usr_cache_enabled()) {
+ /* avoid unnecessary system call to get time if cache is disabled */
+ req_time = acl_get_req_time(resource);
+
+ /* Loop through all the groups and check if any is in the cache */
+ group = groups;
+ delim = ',';
+ while((group = acl_next_token_len(group, delim, &len)) != NULL) {
+ rv = acl_usr_cache_group_len_check(user, dbname, group, len, *req_time);
+ if (rv == LAS_EVAL_TRUE) {
+ /* cached group exists */
+ break;
+ }
+ if (0 != (group = strchr(group+len, delim)))
+ group++;
+ else
+ break;
+ }
+ /* group need not be NULL-terminated */
+ /* If you need to use it, copy it properly */
+ group = 0;
+ }
+
+ if (rv != LAS_EVAL_TRUE) {
+ /* not found in the cache or not one of the groups we want */
+ PListDeleteProp(subject, ACL_ATTR_GROUPS_INDEX, ACL_ATTR_GROUPS);
+ PListInitProp(subject, ACL_ATTR_GROUPS_INDEX, ACL_ATTR_GROUPS, groups, 0);
+ PListDeleteProp(subject, ACL_ATTR_USER_ISMEMBER_INDEX, ACL_ATTR_USER_ISMEMBER);
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USER_ISMEMBER, (void **)&member_of,
+ subject, resource, auth_info, global_auth);
+
+ PListDeleteProp(subject, ACL_ATTR_GROUPS_INDEX, ACL_ATTR_GROUPS);
+
+ if (rv != LAS_EVAL_TRUE && rv != LAS_EVAL_FALSE) {
+ return rv;
+ }
+
+ if (rv == LAS_EVAL_TRUE) {
+ /* User is a member of one of the groups */
+ /* update the user's cache */
+ acl_usr_cache_set_group(user, dbname, member_of, *req_time);
+ }
+ }
+
+ if (rv == LAS_EVAL_TRUE) {
+ retcode = (comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ }
+ else {
+ /* User is not a member of any of the groups */
+ retcode = (comparator == CMP_OP_EQ ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+
+ DBG_PRINT4("%s LASGroupEval: uid = \"%s\" groups = \"%s\"\n",
+ (retcode == LAS_EVAL_FALSE) ? "LAS_EVAL_FALSE"
+ : (retcode == LAS_EVAL_TRUE) ? "LAS_EVAL_TRUE"
+ : "Error",
+ user, attr_pattern);
+
+ return retcode;
+}
+
+
+/* LASGroupFlush
+ * Deallocates any memory previously allocated by the LAS
+ */
+void
+LASGroupFlush(void **las_cookie)
+{
+ /* do nothing */
+ return;
+}
diff --git a/lib/libaccess/lasip.cpp b/lib/libaccess/lasip.cpp
new file mode 100644
index 00000000..2c70a22b
--- /dev/null
+++ b/lib/libaccess/lasip.cpp
@@ -0,0 +1,487 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* aclip.c
+ * This file contains the IP LAS code.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <netsite.h>
+#include <base/plist.h>
+#include <libaccess/nserror.h>
+#include <libaccess/nsauth.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include "lasip.h"
+#include "aclutil.h"
+#include "aclcache.h"
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+
+#define LAS_IP_IS_CONSTANT(x) (((x) == (LASIpTree_t *)LAS_EVAL_TRUE) || ((x) == (LASIpTree_t *)LAS_EVAL_FALSE))
+
+#ifdef UTEST
+extern int LASIpGetIp();
+#endif
+
+static int
+LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop);
+
+/* dotdecimal
+ * Takes netmask and ip strings and returns the numeric values,
+ * accounting for wildards in the ip specification. Wildcards in the
+ * ip override the netmask where they conflict.
+ * INPUT
+ * ipstr e.g. "123.45.67.89"
+ * netmaskstr e.g. "255.255.255.0"
+ * RETURNS
+ * *ip
+ * *netmask e.g. 0xffffff00
+ * result NULL on success or else one of the LAS_EVAL_* codes.
+ */
+int
+dotdecimal(char *ipstr, char *netmaskstr, int *ip, int *netmask)
+{
+ int i;
+ char token[64];
+ char *dotptr; /* location of the "." */
+ int dotidx; /* index of the period char */
+
+ /* Sanity check the patterns */
+
+ /* Netmask can only have digits and periods. */
+ if (strcspn(netmaskstr, "0123456789."))
+ return LAS_EVAL_INVALID;
+
+ /* IP can only have digits, periods and "*" */
+ if (strcspn(ipstr, "0123456789.*"))
+ return LAS_EVAL_INVALID;
+
+ *netmask = *ip = 0; /* Start with "don't care" */
+
+ for (i=0; i<4; i++) {
+ dotptr = strchr(netmaskstr, '.');
+
+ /* copy out the token, then point beyond it */
+ if (dotptr == NULL)
+ strcpy(token, netmaskstr);
+ else {
+ dotidx = dotptr-netmaskstr;
+ strncpy(token, netmaskstr, dotidx);
+ token[dotidx] = '\0';
+ netmaskstr = ++dotptr; /* skip the period */
+ }
+
+ /* Turn into a number and shift left as appropriate */
+ *netmask += (atoi(token))<<(8*(4-i-1));
+
+ if (dotptr == NULL)
+ break;
+ }
+
+ for (i=0; i<4; i++) {
+ dotptr = strchr(ipstr, '.');
+
+ /* copy out the token, then point beyond it */
+ if (dotptr == NULL)
+ strcpy(token, ipstr);
+ else {
+ dotidx = dotptr-ipstr;
+ strncpy(token, ipstr, dotidx);
+ token[dotidx] = '\0';
+ ipstr = ++dotptr;
+ }
+
+ /* check for wildcard */
+ if (strcmp(token, "*") == 0) {
+ switch(i) {
+ case 0:
+ if (dotptr == NULL)
+ *netmask &= 0x00000000;
+ else
+ *netmask &= 0x00ffffff;
+ break;
+ case 1:
+ if (dotptr == NULL)
+ *netmask &= 0xff000000;
+ else
+ *netmask &= 0xff00ffff;
+ break;
+ case 2:
+ if (dotptr == NULL)
+ *netmask &= 0xffff0000;
+ else
+ *netmask &= 0xffff00ff;
+ break;
+ case 3:
+ *netmask &= 0xffffff00;
+ break;
+ }
+ continue;
+ } else {
+ /* Turn into a number and shift left as appropriate */
+ *ip += (atoi(token))<<(8*(4-i-1));
+ }
+
+ /* check for end of string */
+ if (dotptr == NULL) {
+ switch(i) {
+ case 0:
+ *netmask &= 0xff000000;
+ break;
+ case 1:
+ *netmask &= 0xffff0000;
+ break;
+ case 2:
+ *netmask &= 0xffffff00;
+ break;
+ }
+ break;
+ }
+ }
+
+ return (int)NULL;
+}
+
+
+/* LASIpTreeAlloc
+ * Malloc a node and set the actions to LAS_EVAL_FALSE
+ */
+static LASIpTree_t *
+LASIpTreeAllocNode(NSErr_t *errp)
+{
+ LASIpTree_t *newnode;
+
+ newnode = (LASIpTree_t *)PERM_MALLOC(sizeof(LASIpTree_t));
+ if (newnode == NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR5000, ACL_Program, 1, XP_GetAdminStr(DBT_lasiptreeallocNoMemoryN_));
+ return NULL;
+ }
+ newnode->action[0] = (LASIpTree_t *)LAS_EVAL_FALSE;
+ newnode->action[1] = (LASIpTree_t *)LAS_EVAL_FALSE;
+ return newnode;
+}
+
+
+/* LASIpTreeDealloc
+ * Deallocates a Tree starting from a given node down.
+ * INPUT
+ * startnode Starting node to remove. Could be a constant in
+ * which case, just return success.
+ * OUTPUT
+ * N/A
+ */
+static void
+LASIpTreeDealloc(LASIpTree_t *startnode)
+{
+ int i;
+
+ if (startnode == NULL)
+ return;
+
+ /* If this is just a constant then we're done */
+ if (LAS_IP_IS_CONSTANT(startnode))
+ return;
+
+ /* Else recursively call ourself for each branch down */
+ for (i=0; i<2; i++) {
+ if (!(LAS_IP_IS_CONSTANT(startnode->action[i])))
+ LASIpTreeDealloc(startnode->action[i]);
+ }
+
+ /* Now deallocate the local node */
+ PERM_FREE(startnode);
+}
+
+/*
+ * LASIpBuild
+ * INPUT
+ * attr_name The string "ip" - in lower case.
+ * comparator CmpOpEQ or CmpOpNE only
+ * attr_pattern A comma-separated list of IP addresses and netmasks
+ * in dotted-decimal form. Netmasks are optionally
+ * prepended to the IP address using a plus sign. E.g.
+ * 255.255.255.0+123.45.67.89. Any byte in the IP address
+ * (but not the netmask) can be wildcarded using "*"
+ * context A pointer to the IP LAS context structure.
+ * RETURNS
+ * ret code The usual LAS return codes.
+ */
+static int
+LASIpBuild(NSErr_t *errp, char *attr_name, CmpOp_t comparator, char *attr_pattern, LASIpTree_t **treetop)
+{
+ unsigned int delimiter; /* length of valid token */
+ char token[64], token2[64]; /* a single ip[+netmask] */
+ char *curptr; /* current place in attr_pattern */
+ int netmask, ip;
+ char *plusptr;
+ int retcode;
+
+ /* ip address can be delimited by space, tab, comma, or carriage return
+ * only.
+ */
+ curptr = attr_pattern;
+ do {
+ delimiter = strcspn(curptr, ", \t");
+ delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
+ strncpy(token, curptr, delimiter);
+ token[delimiter] = '\0';
+ /* skip all the white space after the token */
+ curptr = strpbrk((curptr+delimiter), "1234567890+.*");
+
+ /* Is there a netmask? */
+ plusptr = strchr(token, '+');
+ if (plusptr == NULL) {
+ if (curptr && (*curptr == '+')) {
+ /* There was a space before (and possibly after) the plus sign*/
+ curptr = strpbrk((++curptr), "1234567890.*");
+ delimiter = strcspn(curptr, ", \t");
+ delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
+ strncpy(token2, curptr, delimiter);
+ token2[delimiter] = '\0';
+ retcode = dotdecimal(token, token2, &ip, &netmask);
+ if (retcode)
+ return (retcode);
+ curptr = strpbrk((++curptr), "1234567890+.*");
+ } else {
+ retcode =dotdecimal(token, "255.255.255.255", &ip, &netmask);
+ if (retcode)
+ return (retcode);
+ }
+ } else {
+ /* token is the IP addr string in both cases */
+ *plusptr ='\0'; /* truncate the string */
+ retcode =dotdecimal(token, ++plusptr, &ip, &netmask);
+ if (retcode)
+ return (retcode);
+ }
+
+ if (LASIpAddPattern(errp, netmask, ip, treetop) != (int)NULL)
+ return LAS_EVAL_INVALID;
+
+ } while ((curptr != NULL) && (delimiter != (int)NULL));
+
+ return (int)NULL;
+}
+
+
+/* LASIpAddPattern
+ * Takes a netmask and IP address and a pointer to an existing IP
+ * tree and adds nodes as appropriate to recognize the new pattern.
+ * INPUT
+ * netmask e.g. 0xffffff00
+ * pattern IP address in 4 bytes
+ * *treetop An existing IP tree or 0 if a new tree
+ * RETURNS
+ * ret code NULL on success, ACL_RES_ERROR on failure
+ * **treetop If this is a new tree, the head of the tree.
+ */
+static int
+LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop)
+{
+ int stopbit; /* Don't care after this point */
+ int curbit; /* current bit we're working on */
+ int curval; /* value of pattern[curbit] */
+ LASIpTree_t *curptr; /* pointer to the current node */
+ LASIpTree_t *newptr;
+
+ /* stop at the first 1 in the netmask from low to high */
+ for (stopbit=0; stopbit<32; stopbit++) {
+ if ((netmask&(1<<stopbit)) != 0)
+ break;
+ }
+
+ /* Special case if there's no tree. Allocate the first node */
+ if (*treetop == (LASIpTree_t *)NULL) { /* No tree at all */
+ curptr = LASIpTreeAllocNode(errp);
+ if (curptr == NULL) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5100, ACL_Program, 1, XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_));
+ return ACL_RES_ERROR;
+ }
+ *treetop = curptr;
+ }
+
+ /* Special case if the netmask is 0.
+ */
+ if (stopbit > 31) {
+ curptr->action[0] = (LASIpTree_t *)LAS_EVAL_TRUE;
+ curptr->action[1] = (LASIpTree_t *)LAS_EVAL_TRUE;
+ return 0;
+ }
+
+
+ /* follow the tree down the pattern path bit by bit until the
+ * end of the tree is reached (i.e. a constant).
+ */
+ for (curbit=31,curptr=*treetop; curbit >= 0; curbit--) {
+
+ /* Is the current bit ON? If so set curval to 1 else 0 */
+ curval = (pattern & (1<<curbit)) ? 1 : 0;
+
+ /* Are we done, if so remove the rest of the tree */
+ if (curbit == stopbit) {
+ LASIpTreeDealloc(curptr->action[curval]);
+ curptr->action[curval] =
+ (LASIpTree_t *)LAS_EVAL_TRUE;
+
+ /* This is the normal exit point. Most other
+ * exits must be due to errors.
+ */
+ return 0;
+ }
+
+ /* Oops reached the end - must allocate */
+ if (LAS_IP_IS_CONSTANT(curptr->action[curval])) {
+ newptr = LASIpTreeAllocNode(errp);
+ if (newptr == NULL) {
+ LASIpTreeDealloc(*treetop);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5110, ACL_Program, 1, XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_1));
+ return ACL_RES_ERROR;
+ }
+ curptr->action[curval] = newptr;
+ }
+
+ /* Keep going down the tree */
+ curptr = curptr->action[curval];
+ }
+
+ return ACL_RES_ERROR;
+}
+
+/* LASIpFlush
+ * Deallocates any memory previously allocated by the LAS
+ */
+void
+LASIpFlush(void **las_cookie)
+{
+ if (*las_cookie == NULL)
+ return;
+
+ LASIpTreeDealloc(((LASIpContext_t *)*las_cookie)->treetop);
+ PERM_FREE(*las_cookie);
+ *las_cookie = NULL;
+ return;
+}
+
+/*
+ * LASIpEval
+ * INPUT
+ * attr_name The string "ip" - in lower case.
+ * comparator CMP_OP_EQ or CMP_OP_NE only
+ * attr_pattern A comma-separated list of IP addresses and netmasks
+ * in dotted-decimal form. Netmasks are optionally
+ * prepended to the IP address using a plus sign. E.g.
+ * 255.255.255.0+123.45.67.89. Any byte in the IP address
+ * (but not the netmask) can be wildcarded using "*"
+ * *cachable Always set to ACL_INDEF_CACHABLE
+ * subject Subject property list
+ * resource Resource property list
+ * auth_info The authentication info if any
+ * RETURNS
+ * ret code The usual LAS return codes.
+ */
+int LASIpEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, ACLCachable_t *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth)
+{
+ int bit;
+ int value;
+ IPAddr_t ip;
+ int retcode;
+ LASIpTree_t *node;
+ LASIpContext_t *context;
+ int rv;
+ char ip_str[124];
+
+ *cachable = ACL_INDEF_CACHABLE;
+
+ if (strcmp(attr_name, "ip") != 0) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5200, ACL_Program, 2, XP_GetAdminStr(DBT_lasIpBuildReceivedRequestForAttr_), attr_name);
+ return LAS_EVAL_INVALID;
+ }
+
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5210, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalIllegalComparatorDN_), comparator_string(comparator));
+ return LAS_EVAL_INVALID;
+ }
+
+ /* GET THE IP ADDR FROM THE SESSION CONTEXT AND STORE IT IN THE
+ * VARIABLE ip.
+ */
+#ifndef UTEST
+ rv = ACL_GetAttribute(errp, ACL_ATTR_IP, (void **)&ip,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ if (subject || resource) {
+ /* Don't ereport if called from ACL_CachableAclList */
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5220, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalUnableToGetSessionAddre_), rv_str);
+ }
+ return LAS_EVAL_FAIL;
+ }
+#else
+ ip = (IPAddr_t)LASIpGetIp();
+#endif
+
+ /* If this is the first time through, build the pattern tree first.
+ */
+ if (*LAS_cookie == NULL) {
+ if (strcspn(attr_pattern, "0123456789.*,+ \t")) {
+ return LAS_EVAL_INVALID;
+ }
+ ACL_CritEnter();
+ if (*LAS_cookie == NULL) { /* must check again */
+ *LAS_cookie = context =
+ (LASIpContext_t *)PERM_MALLOC(sizeof(LASIpContext_t));
+ if (context == NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR5230, ACL_Program, 1, XP_GetAdminStr(DBT_lasipevalUnableToAllocateContext_));
+ ACL_CritExit();
+ return LAS_EVAL_FAIL;
+ }
+ context->treetop = NULL;
+ retcode = LASIpBuild(errp, attr_name, comparator, attr_pattern,
+ &context->treetop);
+ if (retcode) {
+ ACL_CritExit();
+ return (retcode);
+ }
+ }
+ ACL_CritExit();
+ } else
+ context = (LASIpContext *) *LAS_cookie;
+
+ node = context->treetop;
+
+ for (bit=31; bit >=0; bit--) {
+ value = (ip & (IPAddr_t) (1<<bit)) ? 1 : 0;
+ if (LAS_IP_IS_CONSTANT(node->action[value]))
+ /* Reached a result, so return it */
+ if (comparator == CMP_OP_EQ)
+ return((int)(PRSize)node->action[value]);
+ else
+ return(((int)(PRSize)node->action[value] ==
+ LAS_EVAL_TRUE) ?
+ LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+
+ else
+ /* Move on to the next bit */
+ node = node->action[value];
+ }
+
+ /* Cannot reach here. Even a 32 bit mismatch has a conclusion in
+ * the pattern tree.
+ */
+ sprintf(ip_str, "%x", ip);
+ nserrGenerate(errp, ACLERRINTERNAL, ACLERR5240, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalReach32BitsWithoutConcl_), ip_str);
+ return LAS_EVAL_INVALID;
+}
+
diff --git a/lib/libaccess/lasip.h b/lib/libaccess/lasip.h
new file mode 100644
index 00000000..0e162d9b
--- /dev/null
+++ b/lib/libaccess/lasip.h
@@ -0,0 +1,13 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+typedef struct LASIpTree {
+ struct LASIpTree *action[2];
+} LASIpTree_t;
+
+typedef struct LASIpContext {
+ LASIpTree_t *treetop; /* Top of the pattern tree */
+} LASIpContext_t;
diff --git a/lib/libaccess/lastod.cpp b/lib/libaccess/lastod.cpp
new file mode 100644
index 00000000..d304986d
--- /dev/null
+++ b/lib/libaccess/lastod.cpp
@@ -0,0 +1,170 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* Source file for the TimeOfDay and DayOfWeek LAS drivers
+*/
+#include <time.h>
+
+#include <netsite.h>
+#include <base/util.h>
+#include <base/plist.h>
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include "aclutil.h"
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+
+/* Day of the week LAS driver
+ * Note that everything is case-insensitive.
+ * INPUT
+ * attr must be the string "dayofweek".
+ * comparator can only be "=" or "!=".
+ * pattern any sequence of 3-letter day names. I.e. sun, mon,
+ * tue, wed, thu, fri, sat. Comma delimiters can be used
+ * but are not necessary. E.g. mon,TueweDThuFRISat
+ * OUTPUT
+ * cachable Will be set to ACL_NOT_CACHABLE.
+ * return code set to LAS_EVAL_*
+ */
+int
+LASDayOfWeekEval(NSErr_t *errp, char *attr, CmpOp_t comparator, char *pattern,
+ ACLCachable_t *cachable, void **las_cookie, PList_t subject,
+ PList_t resource, PList_t auth_info, PList_t global_auth)
+{
+#ifndef UTEST
+ struct tm *tm_p, tm;
+#endif
+ time_t t;
+ char daystr[5]; /* Current local day in ddd */
+ char lcl_pattern[512];
+ char *compare;
+
+ /* Sanity checking */
+ if (strcmp(attr, "dayofweek") != 0) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5400, ACL_Program, 2, XP_GetAdminStr(DBT_unexpectedAttributeInDayofweekSN_), attr);
+ return LAS_EVAL_INVALID;
+ }
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5410, ACL_Program, 2, XP_GetAdminStr(DBT_illegalComparatorForDayofweekDN_), comparator_string(comparator));
+ return LAS_EVAL_INVALID;
+ }
+ *cachable = ACL_NOT_CACHABLE;
+
+ /* Obtain and format the local time */
+#ifndef UTEST
+ t = time(NULL);
+ tm_p = system_localtime(&t, &tm);
+ util_strftime(daystr, "%a", tm_p);
+#else
+ t = (0x1000000); /* Mon 2120 hr */
+ strftime(daystr, 4, "%a", localtime(&t));
+#endif
+ makelower(daystr);
+ strcpy(lcl_pattern, pattern);
+ makelower(lcl_pattern);
+
+ /* Compare the value to the pattern */
+ compare = strstr(lcl_pattern, daystr);
+
+ if ((compare != NULL) && (comparator == CMP_OP_EQ))
+ return LAS_EVAL_TRUE;
+ if ((compare == NULL) && (comparator == CMP_OP_NE))
+ return LAS_EVAL_TRUE;
+ return LAS_EVAL_FALSE;
+}
+
+
+/* Time of day LAS
+ * INPUT
+ * attr must be "timeofday".
+ * comparator one of =, !=, >, <, >=, <=
+ * pattern HHMM military 24-hour clock. E.g. 0700, 2315.
+ * OUTPUT
+ * cachable will be set to ACL_NOT_CACHABLE.
+ * return code set to LAS_EVAL_*
+ */
+int
+LASTimeOfDayEval(NSErr_t *errp, char *attr, CmpOp_t comparator, char *pattern,
+ ACLCachable_t *cachable, void **LAS_cookie, PList_t subject,
+ PList_t resource, PList_t auth_info, PList_t global_auth)
+{
+#ifndef UTEST
+ struct tm *tm_p, tm;
+#endif
+ time_t t;
+ char timestr[6]; /* Current local time in HHMM */
+ char start[6], end[6];
+ int compare; /* >0, 0, <0 means that current time is greater, equal to, or less than the pattern */
+ char *dash;
+ int intpattern, inttime, intstart, intend;
+
+ if (strcmp(attr, "timeofday") != 0) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5600, ACL_Program, 2, XP_GetAdminStr(DBT_unexpectedAttributeInTimeofdaySN_), attr);
+ return LAS_EVAL_INVALID;
+ }
+ *cachable = ACL_NOT_CACHABLE;
+
+ /* Obtain and format the local time */
+#ifndef UTEST
+ t = time(NULL);
+ tm_p = system_localtime(&t, &tm);
+ util_strftime(timestr, "%H%M", tm_p);
+#else
+ t = (0x1000000); /* Mon 2120 hr */
+ strftime(timestr, 5, "%H%M", localtime(&t));
+#endif
+#ifdef DEBUG
+ printf ("timestr = %s\n", timestr);
+#endif
+ inttime = atoi(timestr);
+
+
+ dash = strchr(pattern, '-');
+ if (dash) {
+ if (comparator != CMP_OP_EQ && comparator != CMP_OP_NE) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5610, ACL_Program, 2, XP_GetAdminStr(DBT_illegalComparatorForTimeOfDayDN_), comparator_string(comparator));
+ return LAS_EVAL_INVALID;
+ }
+
+ strncpy(start, pattern, dash-pattern);
+ start[dash-pattern]='\0';
+ intstart = atoi(start);
+
+ strcpy(end, dash+1);
+ intend = atoi(end);
+
+ if (intend >= intstart) {
+ return(evalComparator(comparator, !(inttime >= intstart && inttime <= intend)));
+ } else { /* range wraps around midnight */
+ return(evalComparator(comparator, !(inttime >= intstart || inttime <= intend)));
+ }
+ }
+
+
+ /* ELSE - Just a single time value given. */
+
+ /* Compare the value to the pattern */
+ intpattern = atoi(pattern);
+ compare = inttime - intpattern;
+
+ /* Test against what the user wanted done */
+ return(evalComparator(comparator, compare));
+}
+
+void
+LASDayOfWeekFlush(void **cookie)
+{
+ return;
+}
+
+void
+LASTimeOfDayFlush(void **cookie)
+{
+ return;
+}
+
diff --git a/lib/libaccess/lasuser.cpp b/lib/libaccess/lasuser.cpp
new file mode 100644
index 00000000..d58f9a3f
--- /dev/null
+++ b/lib/libaccess/lasuser.cpp
@@ -0,0 +1,154 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* lasuser.c
+ * This file contains the User LAS code.
+ */
+
+#include <netsite.h>
+#include <base/shexp.h>
+#include <base/util.h>
+#include <libaccess/las.h>
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+#include "aclutil.h"
+
+#ifdef UTEST
+extern char * LASUserGetUser();
+#endif
+
+
+/*
+ * LASUserEval
+ * INPUT
+ * attr_name The string "user" - in lower case.
+ * comparator CMP_OP_EQ or CMP_OP_NE only
+ * attr_pattern A comma-separated list of users
+ * *cachable Always set to ACL_NOT_CACHABLE.
+ * subject Subject property list
+ * resource Resource property list
+ * auth_info Authentication info, if any
+ * RETURNS
+ * retcode The usual LAS return codes.
+ */
+int LASUserEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, ACLCachable_t *cachable,
+ void **LAS_cookie, PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth)
+{
+ char *uid;
+ char *users;
+ char *user;
+ char *comma;
+ int retcode;
+ int matched;
+ int is_owner;
+ int rv;
+
+ *cachable = ACL_NOT_CACHABLE;
+ *LAS_cookie = (void *)0;
+
+ if (strcmp(attr_name, ACL_ATTR_USER) != 0) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5700, ACL_Program, 2, XP_GetAdminStr(DBT_lasUserEvalReceivedRequestForAtt_), attr_name);
+ return LAS_EVAL_INVALID;
+ }
+
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5710, ACL_Program, 2, XP_GetAdminStr(DBT_lasuserevalIllegalComparatorDN_), comparator_string(comparator));
+ return LAS_EVAL_INVALID;
+ }
+
+ if (!strcmp(attr_pattern, "anyone")) {
+ *cachable = ACL_INDEF_CACHABLE;
+ return comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+ }
+
+ /* get the authenticated user name */
+#ifndef UTEST
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USER, (void **)&uid,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return rv;
+ }
+#else
+ uid = (char *)LASUserGetUser();
+#endif
+
+ /* We have an authenticated user */
+ if (!strcmp(attr_pattern, "all")) {
+ return comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+ }
+
+ users = STRDUP(attr_pattern);
+
+ if (!users) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR5720, ACL_Program, 1,
+ XP_GetAdminStr(DBT_lasuserevalRanOutOfMemoryN_));
+ return LAS_EVAL_FAIL;
+ }
+
+ user = users;
+ matched = 0;
+
+ /* check if the uid is one of the users */
+ while(user != 0 && *user != 0 && !matched) {
+ if ((comma = strchr(user, ',')) != NULL) {
+ *comma++ = 0;
+ }
+
+ /* ignore leading whitespace */
+ while(*user == ' ' || *user == '\t') user++;
+
+ if (*user) {
+ /* ignore trailing whitespace */
+ int len = strlen(user);
+ char *ptr = user+len-1;
+
+ while(*ptr == ' ' || *ptr == '\t') *ptr-- = 0;
+ }
+
+ if (!strcasecmp(user, ACL_ATTR_OWNER)) {
+ rv = ACL_GetAttribute(errp, ACL_ATTR_IS_OWNER, (void **)&is_owner,
+ subject, resource, auth_info, global_auth);
+ if (rv == LAS_EVAL_TRUE)
+ matched = 1;
+ else
+ /* continue checking for next user */
+ user = comma;
+ }
+ else if (!WILDPAT_CASECMP(uid, user)) {
+ /* uid is one of the users */
+ matched = 1;
+ }
+ else {
+ /* continue checking for next user */
+ user = comma;
+ }
+ }
+
+ if (comparator == CMP_OP_EQ) {
+ retcode = (matched ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ }
+ else {
+ retcode = (matched ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+
+ FREE(users);
+ return retcode;
+}
+
+
+/* LASUserFlush
+ * Deallocates any memory previously allocated by the LAS
+ */
+void
+LASUserFlush(void **las_cookie)
+{
+ /* do nothing */
+ return;
+}
diff --git a/lib/libaccess/lcache.h b/lib/libaccess/lcache.h
new file mode 100644
index 00000000..0e39a3a6
--- /dev/null
+++ b/lib/libaccess/lcache.h
@@ -0,0 +1,23 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef CACHE_H
+#define CACHE_H
+
+NSPR_BEGIN_EXTERN_C
+
+extern void ACL_ListHashUpdate(ACLListHandle_t **acllistp);
+extern void ACL_Init(void);
+extern void ACL_CritEnter(void);
+extern void ACL_CritExit(void);
+extern ENTRY *ACL_GetUriHash(ENTRY item, ACTION action);
+extern int ACL_CacheCheck(char *uri, ACLListHandle_t **acllist_p);
+extern void ACL_CacheEnter(char *uri, ACLListHandle_t **acllist_p);
+extern void ACL_CacheAbort(ACLListHandle_t **acllist_p);
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/ldapacl.cpp b/lib/libaccess/ldapacl.cpp
new file mode 100644
index 00000000..ad9d7f7f
--- /dev/null
+++ b/lib/libaccess/ldapacl.cpp
@@ -0,0 +1,822 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* #define DBG_PRINT */
+
+#include <netsite.h>
+#include <base/rwlock.h>
+#include <base/ereport.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include "aclutil.h"
+#include <ldaputil/errors.h>
+#include <ldaputil/certmap.h>
+#include <ldaputil/ldaputil.h>
+#include <ldaputil/dbconf.h>
+#include <ldaputil/ldapauth.h>
+#include <libaccess/authdb.h>
+#include <libaccess/ldapacl.h>
+#include <libaccess/usrcache.h>
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclglobal.h>
+#include <libaccess/aclerror.h>
+
+#define BIG_LINE 1024
+
+static int need_ldap_over_ssl = 0;
+static RWLOCK ldb_rwlock = (RWLOCK)0;
+
+void init_ldb_rwlock ()
+{
+ ldb_rwlock = rwlock_Init();
+}
+
+void ldb_write_rwlock (LDAPDatabase_t *ldb, RWLOCK lock)
+{
+ DBG_PRINT1("ldb_write_rwlock\n");
+ /* Don't lock for local database -- let ldapsdk handle thread safety*/
+ if (!ldapu_is_local_db(ldb))
+ rwlock_WriteLock(lock);
+}
+
+void ldb_read_rwlock (LDAPDatabase_t *ldb, RWLOCK lock)
+{
+ DBG_PRINT1("ldb_read_rwlock\n");
+ /* Don't lock for local database -- let ldapsdk handle thread safety*/
+ if (!ldapu_is_local_db(ldb))
+ rwlock_ReadLock(lock);
+}
+
+void ldb_unlock_rwlock (LDAPDatabase_t *ldb, RWLOCK lock)
+{
+ DBG_PRINT1("ldb_unlock_rwlock\n");
+ /* we don't lock for local database */
+ if (!ldapu_is_local_db(ldb))
+ rwlock_Unlock(lock);
+}
+
+int ACL_NeedLDAPOverSSL ()
+{
+ return need_ldap_over_ssl;
+}
+
+NSAPI_PUBLIC int parse_ldap_url (NSErr_t *errp, ACLDbType_t dbtype,
+ const char *dbname, const char *url,
+ PList_t plist, void **db)
+{
+ LDAPDatabase_t *ldb;
+ char *binddn = 0;
+ char *bindpw = 0;
+ int rv;
+
+ *db = 0;
+
+ if (!url || !*url) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5800, ACL_Program, 1, XP_GetAdminStr(DBT_ldapaclDatabaseUrlIsMissing));
+ return -1;
+ }
+
+ if (!dbname || !*dbname) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5810, ACL_Program, 1, XP_GetAdminStr(DBT_ldapaclDatabaseNameIsMissing));
+ return -1;
+ }
+
+ /* look for binddn and bindpw in the plist */
+ if (plist) {
+ PListFindValue(plist, LDAPU_ATTR_BINDDN, (void **)&binddn, NULL);
+ PListFindValue(plist, LDAPU_ATTR_BINDPW, (void **)&bindpw, NULL);
+ }
+
+ rv = ldapu_url_parse(url, binddn, bindpw, &ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5820, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclErrorParsingLdapUrl), ldapu_err2string(rv));
+ return -1;
+ }
+
+ /* success */
+ *db = ldb;
+
+ /* Check if we need to do LDAP over SSL */
+ if (!need_ldap_over_ssl) {
+ need_ldap_over_ssl = ldb->use_ssl;
+ }
+
+ return 0;
+}
+
+int get_is_valid_password_basic_ldap (NSErr_t *errp, PList_t subject,
+ PList_t resource, PList_t auth_info,
+ PList_t global_auth, void *unused)
+{
+ /* If the raw-user-name and raw-user-password attributes are present then
+ * verify the password against the LDAP database.
+ * Otherwise call AttrGetter for raw-user-name.
+ */
+ char *raw_user;
+ char *raw_pw;
+ char *userdn = 0;
+ int rv;
+ char *dbname;
+ ACLDbType_t dbtype;
+ LDAPDatabase_t *ldb;
+ time_t *req_time = 0;
+ pool_handle_t *subj_pool = PListGetPool(subject)
+
+ DBG_PRINT1("get_is_valid_password_basic_ldap\n");
+ rv = ACL_GetAttribute(errp, ACL_ATTR_RAW_USER, (void **)&raw_user,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return rv;
+ }
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_RAW_PASSWORD, (void **)&raw_pw,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return rv;
+ }
+
+ if (!raw_pw || !*raw_pw) {
+ /* Null password is not allowed in LDAP since most LDAP servers let
+ * the bind call succeed as anonymous login (with limited privileges).
+ */
+ return LAS_EVAL_FALSE;
+ }
+
+ /* Authenticate the raw_user and raw_pw against LDAP database. */
+ rv = ACL_AuthInfoGetDbname(auth_info, &dbname);
+
+ if (rv < 0) {
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5830, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ldapaclUnableToGetDatabaseName), rv_str);
+ return LAS_EVAL_FAIL;
+ }
+
+ rv = ACL_DatabaseFind(errp, dbname, &dbtype, (void **)&ldb);
+
+ if (rv != LAS_EVAL_TRUE) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5840, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ldapaclUnableToGetParsedDatabaseName), dbname);
+ return rv;
+ }
+
+ if (acl_usr_cache_enabled()) {
+ /* avoid unnecessary system call to get time if cache is disabled */
+ req_time = acl_get_req_time(resource);
+
+ /* We have user name and password. */
+ /* Check the cache to see if the password is valid */
+ rv = acl_usr_cache_passwd_check(raw_user, dbname, raw_pw, *req_time,
+ &userdn, subj_pool);
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ }
+
+ if (rv != LAS_EVAL_TRUE) {
+ LDAPMessage *res = 0;
+ const char *some_attrs[] = { "C", 0 };
+ LDAP *ld;
+ char *udn;
+ /* Not found in the cache */
+
+ /* Since we will bind with the user/password and other code relying on
+ * ldb being bound as ldb->binddn and ldb->bindpw may fail. So block
+ * them until we are done.
+ */
+ ldb_write_rwlock(ldb, ldb_rwlock);
+ rv = ldapu_ldap_init_and_bind(ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5850, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclCoudlntInitializeConnectionToLdap), ldapu_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+
+ /* LDAPU_REQ will reconnect & retry once if LDAP server went down */
+ ld = ldb->ld;
+ LDAPU_REQ(rv, ldb, ldapu_find_uid_attrs(ld, raw_user,
+ ldb->basedn, some_attrs,
+ 1, &res));
+
+ if (rv == LDAPU_SUCCESS) {
+ LDAPMessage *entry = ldap_first_entry(ld, res);
+
+ userdn = ldap_get_dn(ld, entry);
+
+ /* LDAPU_REQ will reconnect & retry once if LDAP server went down */
+ LDAPU_REQ(rv, ldb, ldapu_auth_userdn_password(ld, userdn, raw_pw));
+
+ /* Make sure we rebind with the server's DN
+ * ignore errors from ldapu_ldap_rebind -- we will get the same
+ * errors in subsequent calls to LDAP. Return status from the
+ * above call is our only interest now.
+ */
+ ldapu_ldap_rebind(ldb);
+ }
+
+ if (res) ldap_msgfree(res);
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+
+ if (rv == LDAPU_FAILED || rv == LDAP_INVALID_CREDENTIALS) {
+ /* user entry not found or incorrect password */
+ if (userdn) ldap_memfree(userdn);
+ return LAS_EVAL_FALSE;
+ }
+ else if (rv != LDAPU_SUCCESS) {
+ /* some unexpected LDAP error */
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5860, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclPassworkCheckLdapError), ldapu_err2string(rv));
+ if (userdn) ldap_memfree(userdn);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Make an entry in the cache */
+ if (acl_usr_cache_enabled()) {
+ acl_usr_cache_insert(raw_user, dbname, userdn, raw_pw, 0, 0,
+ *req_time);
+ }
+ udn = pool_strdup(subj_pool, userdn);
+ ldap_memfree(userdn);
+ userdn = udn;
+ }
+
+ PListInitProp(subject, ACL_ATTR_IS_VALID_PASSWORD_INDEX, ACL_ATTR_IS_VALID_PASSWORD, raw_user, 0);
+ PListInitProp(subject, ACL_ATTR_USERDN_INDEX, ACL_ATTR_USERDN, userdn, 0);
+ return LAS_EVAL_TRUE;
+}
+
+static int acl_grpcmpfn (const void *groupids, const char *group,
+ const int len)
+{
+ const char *token = (const char *)groupids;
+ int tlen;
+ char delim = ',';
+
+ while((token = acl_next_token_len(token, delim, &tlen)) != NULL) {
+ if (tlen > 0 && tlen == len && !strncmp(token, group, len))
+ return LDAPU_SUCCESS;
+ else if (tlen == 0 || 0 != (token = strchr(token+tlen, delim)))
+ token++;
+ else
+ break;
+ }
+
+ return LDAPU_FAILED;
+}
+
+int get_user_ismember_ldap (NSErr_t *errp, PList_t subject,
+ PList_t resource, PList_t auth_info,
+ PList_t global_auth, void *unused)
+{
+ int retval;
+ int rv;
+ char *userdn;
+ char *groups;
+ char *member_of = 0;
+ LDAPDatabase_t *ldb;
+ char *dbname;
+ ACLDbType_t dbtype;
+
+ DBG_PRINT1("get_user_ismember_ldap\n");
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USERDN, (void **)&userdn, subject,
+ resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return LAS_EVAL_FAIL;
+ }
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_GROUPS, (void **)&groups, subject,
+ resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return rv;
+ }
+
+ rv = ACL_AuthInfoGetDbname(auth_info, &dbname);
+
+ if (rv < 0) {
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5900, ACL_Program, 2, XP_GetAdminStr(DBT_GetUserIsMemberLdapUnabelToGetDatabaseName), rv_str);
+ return rv;
+ }
+
+ rv = ACL_DatabaseFind(errp, dbname, &dbtype, (void **)&ldb);
+
+ if (rv != LAS_EVAL_TRUE) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5910, ACL_Program, 2, XP_GetAdminStr(DBT_GetUserIsMemberLdapUnableToGetParsedDatabaseName), dbname);
+ return rv;
+ }
+
+ ldb_read_rwlock(ldb, ldb_rwlock);
+ rv = ldapu_ldap_init_and_bind(ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5930, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetUserIsMemberLdapCouldntInitializeConnectionToLdap), ldapu_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+
+ /* check if the user is member of any of the groups */
+ /* LDAPU_REQ will reconnect & retry once if LDAP server went down */
+ LDAPU_REQ(rv, ldb, ldapu_auth_userdn_groupids(ldb->ld,
+ userdn,
+ groups,
+ acl_grpcmpfn,
+ ldb->basedn,
+ &member_of));
+
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+
+ if (rv == LDAPU_SUCCESS) {
+ /* User is a member of one of the groups */
+ if (member_of) {
+ PListInitProp(subject, ACL_ATTR_USER_ISMEMBER_INDEX,
+ ACL_ATTR_USER_ISMEMBER,
+ pool_strdup(PListGetPool(subject), member_of), 0);
+ retval = LAS_EVAL_TRUE;
+ }
+ else {
+ /* This shouldn't happen */
+ retval = LAS_EVAL_FALSE;
+ }
+ }
+ else if (rv == LDAPU_FAILED) {
+ /* User is not a member of any of the groups */
+ retval = LAS_EVAL_FALSE;
+ }
+ else {
+ /* unexpected LDAP error */
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5950, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetUserIsMemberLdapError),
+ ldapu_err2string(rv));
+ retval = LAS_EVAL_FAIL;
+ }
+
+ return retval;
+}
+
+
+/* This function returns LDAPU error codes so that the caller can call
+ * ldapu_err2string to get the error string.
+ */
+int acl_map_cert_to_user (NSErr_t *errp, const char *dbname,
+ LDAPDatabase_t *ldb, void *cert,
+ PList_t resource, pool_handle_t *pool,
+ char **user, char **userdn)
+{
+ int rv;
+ LDAPMessage *res;
+ LDAPMessage *entry;
+ char *uid;
+ time_t *req_time = 0;
+
+ if (acl_usr_cache_enabled()) {
+ req_time = acl_get_req_time(resource);
+
+ rv = acl_cert_cache_get_uid (cert, dbname, *req_time, user, userdn,
+ pool);
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ }
+
+ if (rv != LAS_EVAL_TRUE) {
+ /* Not found in the cache */
+
+ ldb_read_rwlock(ldb, ldb_rwlock);
+ rv = ldapu_ldap_init_and_bind(ldb);
+
+ /* LDAPU_REQ will reconnect & retry once if LDAP server went down */
+ /* it sets the variable rv */
+ if (rv == LDAPU_SUCCESS) {
+ char *dn = 0;
+
+ LDAPU_REQ(rv, ldb, ldapu_cert_to_user(cert, ldb->ld, ldb->basedn,
+ &res, &uid));
+
+ if (rv == LDAPU_SUCCESS) {
+ char *dn;
+
+ *user = pool_strdup(pool, uid);
+ if (!*user) rv = LDAPU_ERR_OUT_OF_MEMORY;
+ free(uid);
+
+ entry = ldap_first_entry(ldb->ld, res);
+ dn = ldap_get_dn(ldb->ld, entry);
+ if (acl_usr_cache_enabled()) {
+ acl_cert_cache_insert (cert, dbname, *user, dn, *req_time);
+ }
+ *userdn = dn ? pool_strdup(pool, dn) : 0;
+ if (!*userdn) rv = LDAPU_ERR_OUT_OF_MEMORY;
+ ldap_memfree(dn);
+ }
+ if (res) ldap_msgfree(res);
+ }
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+ }
+ else {
+ rv = LDAPU_SUCCESS;
+ }
+
+ return rv;
+}
+
+
+/*
+ * ACL_LDAPDatabaseHandle -
+ * Finds the internal structure representing the 'dbname'. If it is an LDAP
+ * database, returns the 'LDAP *ld' pointer. Also, binds to the LDAP server.
+ * The LDAP *ld handle can be used in calls to LDAP API.
+ * Returns LAS_EVAL_TRUE if successful, otherwise logs an error in
+ * LOG_SECURITY and returns LAS_EVAL_FAIL.
+ */
+int ACL_LDAPDatabaseHandle (NSErr_t *errp, const char *dbname, LDAP **ld,
+ char **basedn)
+{
+ int rv;
+ ACLDbType_t dbtype;
+ void *db;
+ LDAPDatabase_t *ldb;
+
+ *ld = 0;
+ if (!dbname || !*dbname) dbname = DBCONF_DEFAULT_DBNAME;
+
+ /* Check if the ldb is already in the ACLUserLdbHash */
+ ldb = (LDAPDatabase_t *)PR_HashTableLookup(ACLUserLdbHash, dbname);
+
+ if (!ldb) {
+
+ rv = ACL_DatabaseFind(errp, dbname, &dbtype, &db);
+
+ if (rv != LAS_EVAL_TRUE) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR6000, ACL_Program, 2, XP_GetAdminStr(DBT_LdapDatabaseHandleNotARegisteredDatabase), dbname);
+ return LAS_EVAL_FAIL;
+ }
+
+ if (!ACL_DbTypeIsEqual(errp, dbtype, ACL_DbTypeLdap)) {
+ /* Not an LDAP database -- error */
+ nserrGenerate(errp, ACLERRINVAL, ACLERR6010, ACL_Program, 2, XP_GetAdminStr(DBT_LdapDatabaseHandleNotAnLdapDatabase), dbname);
+ return LAS_EVAL_FAIL;
+ }
+
+ ldb = ldapu_copy_LDAPDatabase_t((LDAPDatabase_t *)db);
+
+ if (!ldb) {
+ /* Not an LDAP database -- error */
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR6020, ACL_Program, 1, XP_GetAdminStr(DBT_LdapDatabaseHandleOutOfMemory));
+ return LAS_EVAL_FAIL;
+ }
+
+ PR_HashTableAdd(ACLUserLdbHash, PERM_STRDUP(dbname), ldb);
+ }
+
+ if (!ldb->ld) {
+ rv = ldapu_ldap_init_and_bind(ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR6030, ACL_Program, 2, XP_GetAdminStr(DBT_LdapDatabaseHandleCouldntInitializeConnectionToLdap), ldapu_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+ }
+
+ /*
+ * Force the rebind -- we don't know whether the customer has used this ld
+ * to bind as somebody else. It will also check if the LDAP server is up
+ * and running, reestablish the connection if the LDAP server has rebooted
+ * since it was last used.
+ */
+ rv = ldapu_ldap_rebind(ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR6040, ACL_Program, 2, XP_GetAdminStr(DBT_LdapDatabaseHandleCouldntBindToLdapServer), ldapu_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+
+ *ld = ldb->ld;
+
+ if (basedn) {
+ /* They asked for the basedn too */
+ *basedn = PERM_STRDUP(ldb->basedn);
+ }
+
+ return LAS_EVAL_TRUE;
+}
+
+int get_userdn_ldap (NSErr_t *errp, PList_t subject,
+ PList_t resource, PList_t auth_info,
+ PList_t global_auth, void *unused)
+{
+ char *uid;
+ char *dbname;
+ char *userdn;
+ time_t *req_time = 0;
+ pool_handle_t *subj_pool = PListGetPool(subject);
+ int rv;
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USER, (void **)&uid, subject,
+ resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return LAS_EVAL_FAIL;
+ }
+
+ /* The getter for ACL_ATTR_USER may have put the USERDN on the PList */
+ rv = PListGetValue(subject, ACL_ATTR_USERDN_INDEX, (void **)&userdn, NULL);
+
+ if (rv >= 0) {
+ /* Nothing to do */
+ return LAS_EVAL_TRUE;
+ }
+
+ rv = ACL_AuthInfoGetDbname(auth_info, &dbname);
+
+ if (rv < 0) {
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5830, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ldapaclUnableToGetDatabaseName), rv_str);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Check if the userdn is available in the usr_cache */
+ if (acl_usr_cache_enabled()) {
+ /* avoid unnecessary system call to get time if cache is disabled */
+ req_time = acl_get_req_time(resource);
+
+ rv = acl_usr_cache_get_userdn(uid, dbname, *req_time, &userdn,
+ subj_pool);
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ }
+
+ if (rv == LAS_EVAL_TRUE) {
+ /* Found in the cache */
+ PListInitProp(subject, ACL_ATTR_USERDN_INDEX, ACL_ATTR_USERDN,
+ userdn, 0);
+ }
+ else {
+ ACLDbType_t dbtype;
+ LDAPDatabase_t *ldb = 0;
+
+ /* Perform LDAP lookup */
+ rv = ACL_DatabaseFind(errp, dbname, &dbtype, (void **)&ldb);
+
+ if (rv != LAS_EVAL_TRUE) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5840, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ldapaclUnableToGetParsedDatabaseName), dbname);
+ return rv;
+ }
+
+ ldb_read_rwlock(ldb, ldb_rwlock);
+ rv = ldapu_ldap_init_and_bind(ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5850, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclCoudlntInitializeConnectionToLdap), ldapu_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+
+ LDAPU_REQ(rv, ldb, ldapu_find_userdn(ldb->ld, uid, ldb->basedn,
+ &userdn));
+
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+
+ if (rv == LDAPU_SUCCESS) {
+ /* Found it. Store it in the cache also. */
+ PListInitProp(subject, ACL_ATTR_USERDN_INDEX, ACL_ATTR_USERDN,
+ pool_strdup(subj_pool, userdn), 0);
+ if (acl_usr_cache_enabled()) {
+ acl_usr_cache_set_userdn(uid, dbname, userdn, *req_time);
+ }
+ ldapu_free(userdn);
+ rv = LAS_EVAL_TRUE;
+ }
+ else if (rv == LDAPU_FAILED) {
+ /* Not found but not an error */
+ rv = LAS_EVAL_FALSE;
+ }
+ else {
+ /* some unexpected LDAP error */
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5860, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclPassworkCheckLdapError), ldapu_err2string(rv));
+ rv = LAS_EVAL_FAIL;
+ }
+ }
+
+ return rv;
+}
+
+/* Attr getter for LDAP database to check if the user exists */
+int get_user_exists_ldap (NSErr_t *errp, PList_t subject,
+ PList_t resource, PList_t auth_info,
+ PList_t global_auth, void *unused)
+{
+ int rv;
+ char *user;
+ char *userdn;
+
+ /* See if the userdn is already available */
+ rv = PListGetValue(subject, ACL_ATTR_USERDN_INDEX, (void **)&userdn, NULL);
+
+ if (rv >= 0) {
+ /* Check if the DN is still valid against the database */
+ /* Get the database name */
+ char *dbname;
+ ACLDbType_t dbtype;
+ LDAPDatabase_t *ldb = 0;
+ LDAPMessage *res;
+ const char *some_attrs[] = { "c", 0 };
+
+ rv = ACL_AuthInfoGetDbname(auth_info, &dbname);
+
+ if (rv < 0) {
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5830, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ldapaclUnableToGetDatabaseName), rv_str);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Perform LDAP lookup */
+ rv = ACL_DatabaseFind(errp, dbname, &dbtype, (void **)&ldb);
+
+ if (rv != LAS_EVAL_TRUE) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5840, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ldapaclUnableToGetParsedDatabaseName), dbname);
+ return rv;
+ }
+
+ ldb_read_rwlock(ldb, ldb_rwlock);
+ rv = ldapu_ldap_init_and_bind(ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5850, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclCoudlntInitializeConnectionToLdap), ldapu_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+
+ LDAPU_REQ(rv, ldb, ldapu_find (ldb->ld, ldb->basedn, LDAP_SCOPE_BASE,
+ NULL, some_attrs, 1, &res));
+
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+
+ if (rv == LDAPU_SUCCESS) {
+ /* Found it. */
+ rv = LAS_EVAL_TRUE;
+ }
+ else if (rv == LDAPU_FAILED) {
+ /* Not found but not an error */
+ rv = LAS_EVAL_FALSE;
+ }
+ else {
+ /* some unexpected LDAP error */
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5860, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclPassworkCheckLdapError), ldapu_err2string(rv));
+ rv = LAS_EVAL_FAIL;
+ }
+ }
+ else {
+ /* If the DN doesn't exist, should we just return an error ? */
+ /* If yes, we don't need rest of the code */
+
+ /* If we don't have a DN, we must have a user at least */
+ rv = PListGetValue(subject, ACL_ATTR_USER_INDEX, (void **)&user, NULL);
+
+ if (rv < 0) {
+ /* We don't even have a user name */
+ return LAS_EVAL_FAIL;
+ }
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USERDN, (void **)&userdn, subject,
+ resource, auth_info, global_auth);
+ }
+
+ /* If we can get the userdn then the user exists */
+ if (rv == LAS_EVAL_TRUE) {
+ PListInitProp(subject, ACL_ATTR_USER_EXISTS_INDEX,
+ ACL_ATTR_USER_EXISTS, userdn, 0);
+ }
+
+ return rv;
+}
+
+/* acl_user_exists - */
+/* Function to check if the user still exists */
+/* This function works for all kinds of databases */
+/* Returns 0 on success and -ve value on failure */
+NSAPI_PUBLIC int acl_user_exists (const char *user, const char *userdn,
+ const char *dbname, const int logerr)
+{
+ NSErr_t err = NSERRINIT;
+ NSErr_t *errp = &err;
+ pool_handle_t *pool = 0;
+ time_t *req_time = 0;
+ PList_t subject = 0;
+ PList_t resource = 0;
+ PList_t auth_info = 0;
+ PList_t global_auth = NULL;
+ char *olddn = 0;
+ int rv;
+
+ /* Check if the userdn is available in the usr_cache */
+ if (acl_usr_cache_enabled() && userdn) {
+ /* avoid unnecessary system call to get time if cache is disabled */
+ req_time = (time_t *)MALLOC(sizeof(time_t));
+
+ if (req_time) {
+ time(req_time);
+ rv = acl_usr_cache_userdn_check(user, dbname, userdn, *req_time);
+ FREE((void *)req_time);
+ }
+
+ if (rv == LAS_EVAL_TRUE)
+ {
+ /* Found in the cache with the same DN */
+ return 0;
+ }
+ }
+
+ pool = pool_create();
+ subject = PListCreate(pool, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ resource = PListCreate(pool, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ auth_info = PListCreate(pool, ACL_ATTR_INDEX_MAX, NULL, NULL);
+
+ if (!pool || !subject || !resource || !auth_info) {
+ /* ran out of memory */
+ goto no_mem;
+ }
+
+ /* store a pointer to the user rather than a copy */
+ rv = PListInitProp(subject, ACL_ATTR_USER_INDEX, ACL_ATTR_USER,
+ user, 0);
+ if (rv < 0) { /* Plist error */ goto plist_err; }
+
+ if (userdn && *userdn) {
+ /* store a pointer to the userdn rather than a copy */
+ rv = PListInitProp(subject, ACL_ATTR_USERDN_INDEX, ACL_ATTR_USERDN,
+ userdn, 0);
+ if (rv < 0) { /* Plist error */ goto plist_err; }
+ }
+
+ /* store the cached dbname on auth_info */
+ rv = ACL_AuthInfoSetDbname(errp, auth_info, dbname);
+ if (rv < 0) { /* auth_info error */ goto err; }
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USER_EXISTS, (void **)&user,
+ subject, resource, auth_info, global_auth);
+
+ if (rv == LAS_EVAL_TRUE) {
+ /* User still exists */
+ rv = 0;
+ }
+ else if (rv == LAS_EVAL_FALSE) {
+ /* User doesn't exist anymore */
+ nserrGenerate(errp, ACLERRFAIL, 5880, ACL_Program, 2, XP_GetAdminStr(DBT_AclUserExistsNot), user);
+ goto err;
+ }
+ else {
+ /* Unexpected error while checking the existence of the user */
+ goto err;
+ }
+
+ goto done;
+
+plist_err:
+ nserrGenerate(errp, ACLERRFAIL, 5890, ACL_Program, 1, XP_GetAdminStr(DBT_AclUserPlistError));
+ goto err;
+
+no_mem:
+ nserrGenerate(errp, ACLERRNOMEM, 5870, ACL_Program, 1, XP_GetAdminStr(DBT_AclUserExistsOutOfMemory));
+ goto err;
+
+err:
+ if (logerr) {
+ /* Unexpected error while checking the existence of the user */
+ char buf[BIG_LINE];
+ /* generate error message (upto depth 6) into buf */
+ aclErrorFmt(errp, buf, BIG_LINE, 6);
+ ereport(LOG_SECURITY, "Error while checking the existence of user: %s", buf);
+ }
+
+ nserrDispose(errp);
+ rv = -1;
+
+done:
+ /* Destroy the PLists & the pool */
+ if (subject) PListDestroy(subject);
+ if (resource) PListDestroy(resource);
+ if (auth_info) PListDestroy(auth_info);
+ if (pool) pool_destroy(pool);
+ return rv;
+}
diff --git a/lib/libaccess/ldapauth.h b/lib/libaccess/ldapauth.h
new file mode 100644
index 00000000..409aa6e9
--- /dev/null
+++ b/lib/libaccess/ldapauth.h
@@ -0,0 +1,42 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef LDAP_AUTH_H
+#define LDAP_AUTH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ldap/ldap.h"
+
+const int LDAP_ACL_SUCCESS = 0;
+const int LDAP_ACL_FAILED = -1;
+
+extern int ldap_auth_userdn_groupdn (LDAP *ld, char *userdn,
+ char *groupdn);
+extern int ldap_auth_uid_groupdn (LDAP *ld, char *uid,
+ char *groupdn);
+extern int ldap_auth_uid_groupid (LDAP *ld, char *uid,
+ char *groupid);
+extern int ldap_auth_userdn_groupid (LDAP *ld, char *userdn,
+ char *groupid);
+extern int ldap_auth_userdn_attrfilter (LDAP *ld, char *userdn,
+ char *attrfilter);
+extern int ldap_auth_uid_attrfilter (LDAP *ld, char *uid,
+ char *attrfilter);
+extern int ldap_auth_userdn_password (LDAP *ld, char *userdn,
+ char *password);
+extern int ldap_find_uid (LDAP *ld, char *uid, LDAPMessage **res);
+extern int ldap_auth_uid_password (LDAP *ld, char *uid,
+ char *password);
+extern LDAP *init_ldap();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDAP_AUTH_H */
diff --git a/lib/libaccess/leval.h b/lib/libaccess/leval.h
new file mode 100644
index 00000000..22d3ee8a
--- /dev/null
+++ b/lib/libaccess/leval.h
@@ -0,0 +1,18 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef LEVAL_H
+#define LEVAL_H
+
+NSPR_BEGIN_EXTERN_C
+
+int
+freeLAS(NSErr_t *errp, char *attribute, void **las_cookie);
+
+NSPR_END_EXTERN_C
+
+#endif
+
diff --git a/lib/libaccess/lparse.h b/lib/libaccess/lparse.h
new file mode 100644
index 00000000..6386d56e
--- /dev/null
+++ b/lib/libaccess/lparse.h
@@ -0,0 +1,27 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * This grammar is intended to parse the version 3.0 ACL
+ * and output an ACLParseACE_t structure.
+ */
+
+#ifndef LPARSE_H
+#define LPARSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int aclPushListHandle(ACLListHandle_t *handle);
+extern int aclparse(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/libaccess/method.cpp b/lib/libaccess/method.cpp
new file mode 100644
index 00000000..1425ad55
--- /dev/null
+++ b/lib/libaccess/method.cpp
@@ -0,0 +1,163 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <netsite.h>
+#include <libaccess/las.h>
+#include <libaccess/acl.h>
+#include <libaccess/aclerror.h>
+#include <libaccess/dbtlibaccess.h>
+#include "aclpriv.h"
+
+NSAPI_PUBLIC int ACL_ModuleRegister (NSErr_t *errp, const char *module_name,
+ AclModuleInitFunc func)
+{
+ int rv;
+
+ if (!module_name || !*module_name) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4200, ACL_Program, 1,
+ XP_GetAdminStr(DBT_ModuleRegisterModuleNameMissing));
+ return -1;
+ }
+
+ rv = (*func)(errp);
+
+ if (rv < 0) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4210, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ModuleRegisterFailed), module_name);
+ return rv;
+ }
+
+ return 0;
+}
+
+
+static int attr_getter_is_matching(NSErr_t *errp, ACLAttrGetter_t *getter,
+ ACLMethod_t method, ACLDbType_t dbtype)
+{
+ if ((ACL_MethodIsEqual(errp, getter->method, method) ||
+ ACL_MethodIsEqual(errp, getter->method, ACL_METHOD_ANY)) &&
+ (ACL_DbTypeIsEqual(errp, getter->dbtype, dbtype) ||
+ ACL_DbTypeIsEqual(errp, getter->dbtype, ACL_DBTYPE_ANY)))
+ {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+NSAPI_PUBLIC int ACL_GetAttribute(NSErr_t *errp, const char *attr, void **val,
+ PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth)
+{
+ int rv;
+ void *attrval;
+ ACLAttrGetterFn_t func;
+ ACLAttrGetterList_t getters;
+ ACLAttrGetter_t *getter;
+ ACLMethod_t method;
+ ACLDbType_t dbtype;
+
+ /* If subject PList is NULL, we will fail anyway */
+ if (!subject) return LAS_EVAL_FAIL;
+
+ /* Is the attribute already present in the subject property list? */
+
+ rv = PListFindValue(subject, attr, &attrval, NULL);
+ if (rv >= 0) {
+
+ /* Yes, take it from there */
+ *val = attrval;
+ return LAS_EVAL_TRUE;
+ }
+
+ /* Get the authentication method and database type */
+
+ rv = ACL_AuthInfoGetMethod(errp, auth_info, &method);
+
+ if (rv < 0) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4300, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetAttributeCouldntDetermineMethod), attr);
+ return LAS_EVAL_FAIL;
+ }
+
+ rv = ACL_AuthInfoGetDbType (errp, auth_info, &dbtype);
+
+ if (rv < 0) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4380, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ReadDbMapFileCouldntDetermineDbtype), attr);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Get the list of attribute getters */
+
+ rv = ACL_AttrGetterFind(errp, attr, &getters);
+
+ if ((rv < 0) || (getters == 0)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4310, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetAttributeCouldntLocateGetter), attr);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Iterate over each getter and see if it should be called
+ * Call each matching getter until a getter which doesn't decline is
+ * found.
+ */
+
+ for (getter = ACL_AttrGetterFirst(&getters);
+ getter != 0;
+ getter = ACL_AttrGetterNext(&getters, getter)) {
+
+ /* Require matching method and database type */
+
+ if (attr_getter_is_matching(errp, getter, method, dbtype)) {
+
+ /* Call the getter function */
+ func = getter->fn;
+ rv = (*func)(errp, subject, resource, auth_info, global_auth,
+ getter->arg);
+
+ /* Did the getter succeed? */
+ if (rv == LAS_EVAL_TRUE) {
+
+ /*
+ * Yes, it should leave the attribute on the subject
+ * property list.
+ */
+ rv = PListFindValue(subject, attr, (void **)&attrval, NULL);
+
+ if (rv < 0) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4320, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetAttributeDidntSetAttr), attr);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Got it */
+ *val = attrval;
+ return LAS_EVAL_TRUE;
+ }
+
+ /* Did the getter decline? */
+ if (rv != LAS_EVAL_DECLINE) {
+
+ /* No, did it fail to get the attribute */
+ if (rv == LAS_EVAL_FAIL || rv == LAS_EVAL_INVALID) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4330, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetAttributeDidntGetAttr), attr);
+ }
+
+ return rv;
+ }
+ }
+ }
+
+ /* If we fall out of the loop, all the getters declined */
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4340, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetAttributeAllGettersDeclined), attr);
+ return LAS_EVAL_FAIL;
+}
+
diff --git a/lib/libaccess/nsadb.cpp b/lib/libaccess/nsadb.cpp
new file mode 100644
index 00000000..a87951b8
--- /dev/null
+++ b/lib/libaccess/nsadb.cpp
@@ -0,0 +1,582 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsadb.c)
+ *
+ * This module contains routines for retrieving information from
+ * a Netscape authentication database. An authentication database
+ * consists of a user database and a group database. This module
+ * implements an authentication database based on Netscape user and
+ * group databases defined in nsuser.h and nsgroup.h, which in turn
+ * are based on the Netscape (server) database implementation
+ * defined in nsdb.h. The interface for managing information in
+ * an authentication database is described separately in nsamgmt.h.
+ */
+
+#include <base/systems.h>
+#include <netsite.h>
+#include <base/file.h>
+#include <base/fsmutex.h>
+#include <libaccess/nsdbmgmt.h>
+#define __PRIVATE_NSADB
+#include <libaccess/nsadb.h>
+#include <libaccess/nsuser.h>
+#include <libaccess/nsgroup.h>
+
+/*
+ * Description (NSADB_AuthIF)
+ *
+ * This structure defines a generic authentication database
+ * interface for this module. It does not currently support
+ * user/group id lookup.
+ */
+AuthIF_t NSADB_AuthIF = {
+ 0, /* find user/group by id */
+ nsadbFindByName, /* find user/group by name */
+ nsadbIdToName, /* lookup name for user/group id */
+ nsadbOpen, /* open a named database */
+ nsadbClose, /* close a database */
+};
+
+/*
+ * Description (nsadbClose)
+ *
+ * This function closes an authentication database previously opened
+ * via nsadbOpen().
+ *
+ * Arguments:
+ *
+ * authdb - handle returned by nsadbOpen()
+ * flags - unused (must be zero)
+ */
+
+NSAPI_PUBLIC void nsadbClose(void * authdb, int flags)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+
+ if (adb->adb_userdb != 0) {
+ ndbClose(adb->adb_userdb, 0);
+ }
+
+ if (adb->adb_groupdb != 0) {
+ ndbClose(adb->adb_groupdb, 0);
+ }
+
+#if defined(CLIENT_AUTH)
+ nsadbCloseCerts(authdb, flags);
+#endif
+
+ if (adb->adb_dbname) {
+ FREE(adb->adb_dbname);
+ }
+
+ FREE(adb);
+}
+
+/*
+ * Description (nsadbOpen)
+ *
+ * This function is used to open an authentication database.
+ * The caller specifies a name for the database, which is actually
+ * the name of a directory containing the files which comprise the
+ * database. The caller also indicates whether this is a new
+ * database, in which case it is created.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * adbname - name of this database (directory)
+ * flags - open flags:
+ * AIF_CREATE - new database (create)
+ * rptr - pointer to returned handle
+ *
+ * Returns:
+ *
+ * A handle for accessing the database is always returned via 'rptr'
+ * unless there was a shortage of dynamic memory, in which case a
+ * null handle is returned. The return value of the function is
+ * 0 if it completes successfully. An error is indicated by a
+ * negative return value (see nsautherr.h).
+ */
+
+NSAPI_PUBLIC int nsadbOpen(NSErr_t * errp,
+ char * adbname, int flags, void **rptr)
+{
+ AuthDB_t * authdb = 0; /* pointer to database descriptor */
+ SYS_DIR dbdir; /* database directory handle */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Make sure we have a place to return the database handle */
+ if (rptr == 0) goto err_inval;
+
+ /* Allocate the database descriptor */
+ authdb = (AuthDB_t *)MALLOC(sizeof(AuthDB_t));
+ if (authdb == 0) goto err_nomem;
+
+ /* Return the descriptor pointer as the database handle */
+ *rptr = (void *)authdb;
+
+ authdb->adb_dbname = STRDUP(adbname);
+ authdb->adb_userdb = 0;
+ authdb->adb_groupdb = 0;
+#if defined(CLIENT_AUTH)
+ authdb->adb_certdb = 0;
+ authdb->adb_certlock = 0;
+ authdb->adb_certnm = 0;
+#endif
+ authdb->adb_flags = 0;
+
+ /* See if the database directory exists */
+ dbdir = dir_open(adbname);
+ if (dbdir == 0) {
+ /* No, create it if this is a new database, else error */
+ if (flags & AIF_CREATE) {
+ rv = dir_create(adbname);
+ if (rv < 0) goto err_mkdir;
+ authdb->adb_flags |= ADBF_NEW;
+ }
+ else goto err_dopen;
+ }
+ else {
+ /* Ok, it's there */
+ dir_close(dbdir);
+ }
+
+ return 0;
+
+ err_inval:
+ eid = NSAUERR3000;
+ rv = NSAERRINVAL;
+ goto err_ret;
+
+ err_nomem:
+ /* Error - insufficient dynamic memory */
+ eid = NSAUERR3020;
+ rv = NSAERRNOMEM;
+ goto err_ret;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ goto punt;
+
+ err_mkdir:
+ eid = NSAUERR3040;
+ rv = NSAERRMKDIR;
+ goto err_dir;
+
+ err_dopen:
+ eid = NSAUERR3060;
+ rv = NSAERROPEN;
+ goto err_dir;
+
+ err_dir:
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, adbname);
+ goto punt;
+
+ punt:
+ /* Fatal error - free database descriptor and return null handle */
+ if (authdb) {
+ if (authdb->adb_dbname) {
+ FREE(authdb->adb_dbname);
+ }
+ FREE(authdb);
+ }
+
+ if (rptr) *rptr = 0;
+
+ return rv;
+}
+
+/*
+ * Description (nsadbOpenUsers)
+ *
+ * This function is called to open the users subdatabase of an
+ * open authentication database. The caller specifies flags to
+ * indicate whether read or write access is required. This
+ * function is normally called only by routines below the
+ * nsadbOpen() API, in response to perform particular operations
+ * on user or group objects. If the open is successful, the
+ * resulting handle is stored in the AuthDB_t structure.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * flags - open flags:
+ * ADBF_UREAD - open for read
+ * ADBF_UWRITE - open for read/write
+ * Returns:
+ *
+ * The return value is zero if the operation is successfully
+ * completed. An error is indicated by a negative return value
+ * (see nsautherr.h), and an error frame is generated if an error
+ * frame list was provided.
+ */
+
+NSAPI_PUBLIC int nsadbOpenUsers(NSErr_t * errp, void * authdb, int flags)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ char * userfn = 0; /* user database name */
+ int dblen; /* strlen(adb_dbname) */
+ int uversion; /* user database version number */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ if (adb == 0) goto err_inval;
+
+ /* Is the user database already open? */
+ if (adb->adb_userdb != 0) {
+
+ /* Yes, is it open for the desired access? */
+ if (adb->adb_flags & flags) {
+
+ /* Yes, that was easy */
+ return 0;
+ }
+ }
+ else {
+
+ /* We need to open the database */
+
+ /* Allocate space for the user database filename */
+ dblen = strlen(adb->adb_dbname);
+
+ userfn = (char *)MALLOC(dblen + strlen(ADBUSERDBNAME) + 2);
+ if (userfn == 0) goto err_nomem;
+
+ /* Construct user database name */
+ strcpy(userfn, adb->adb_dbname);
+
+ /* Put in a '/' (or '\') if it's not there */
+ if (userfn[dblen-1] != FILE_PATHSEP) {
+ userfn[dblen] = FILE_PATHSEP;
+ userfn[dblen+1] = 0;
+ ++dblen;
+ }
+
+ strcpy(&userfn[dblen], ADBUSERDBNAME);
+
+ adb->adb_userdb = ndbOpen(errp,
+ userfn, 0, NDB_TYPE_USERDB, &uversion);
+ if (adb->adb_userdb == 0) goto err_uopen;
+
+ FREE(userfn);
+ }
+
+ /*
+ * We don't really reopen the database to get the desired
+ * access mode, since that is handled at the nsdb level.
+ * But we do update the flags, just for the record.
+ */
+ adb->adb_flags &= ~(ADBF_UREAD|ADBF_UWRITE);
+ if (flags & ADBF_UWRITE) adb->adb_flags |= ADBF_UWRITE;
+ else adb->adb_flags |= ADBF_UREAD;
+
+ return 0;
+
+ err_inval:
+ eid = NSAUERR3200;
+ rv = NSAERRINVAL;
+ goto err_ret;
+
+ err_nomem:
+ eid = NSAUERR3220;
+ rv = NSAERRNOMEM;
+ goto err_ret;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ goto punt;
+
+ err_uopen:
+ eid = NSAUERR3240;
+ rv = NSAERROPEN;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, userfn);
+ goto punt;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbOpenGroups)
+ *
+ * This function is called to open the groups subdatabase of an
+ * open authentication database. The caller specifies flags to
+ * indicate whether read or write access is required. This
+ * function is normally called only by routines below the
+ * nsadbOpen() API, in response to perform particular operations
+ * on user or group objects. If the open is successful, the
+ * resulting handle is stored in the AuthDB_t structure.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * flags - open flags:
+ * ADBF_GREAD - open for read
+ * ADBF_GWRITE - open for read/write
+ * Returns:
+ *
+ * The return value is zero if the operation is successfully
+ * completed. An error is indicated by a negative return value
+ * (see nsautherr.h), and an error frame is generated if an error
+ * frame list was provided.
+ */
+
+NSAPI_PUBLIC int nsadbOpenGroups(NSErr_t * errp, void * authdb, int flags)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ char * groupfn = 0; /* group database name */
+ int dblen; /* strlen(adb_dbname) */
+ int gversion; /* group database version number */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ if (adb == 0) goto err_inval;
+
+ /* Is the group database already open? */
+ if (adb->adb_groupdb != 0) {
+
+ /* Yes, is it open for the desired access? */
+ if (adb->adb_flags & flags) {
+
+ /* Yes, that was easy */
+ return 0;
+ }
+ }
+ else {
+
+ /* We need to open the database */
+
+ /* Allocate space for the group database filename */
+ dblen = strlen(adb->adb_dbname);
+
+ groupfn = (char *)MALLOC(dblen + strlen(ADBGROUPDBNAME) + 2);
+ if (groupfn == 0) goto err_nomem;
+
+ /* Construct group database name */
+ strcpy(groupfn, adb->adb_dbname);
+
+ /* Put in a '/' (or '\') if it's not there */
+ if (groupfn[dblen-1] != FILE_PATHSEP) {
+ groupfn[dblen] = FILE_PATHSEP;
+ groupfn[dblen+1] = 0;
+ ++dblen;
+ }
+
+ strcpy(&groupfn[dblen], ADBGROUPDBNAME);
+
+ adb->adb_groupdb = ndbOpen(errp,
+ groupfn, 0, NDB_TYPE_GROUPDB, &gversion);
+ if (adb->adb_groupdb == 0) goto err_gopen;
+
+ FREE(groupfn);
+ }
+
+ /*
+ * We don't really reopen the database to get the desired
+ * access mode, since that is handled at the nsdb level.
+ * But we do update the flags, just for the record.
+ */
+ adb->adb_flags &= ~(ADBF_GREAD|ADBF_GWRITE);
+ if (flags & ADBF_GWRITE) adb->adb_flags |= ADBF_GWRITE;
+ else adb->adb_flags |= ADBF_GREAD;
+
+ return 0;
+
+ err_inval:
+ eid = NSAUERR3300;
+ rv = NSAERRINVAL;
+ goto err_ret;
+
+ err_nomem:
+ eid = NSAUERR3320;
+ rv = NSAERRNOMEM;
+ goto err_ret;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ goto punt;
+
+ err_gopen:
+ eid = NSAUERR3340;
+ rv = NSAERROPEN;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, groupfn);
+ goto punt;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbIdToName)
+ *
+ * This function looks up a specified user or group id in the
+ * authentication database. The name associated with the specified
+ * id is returned.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * id - user or group id
+ * flags - AIF_USER or AIF_GROUP (defined in nsauth.h)
+ * rptr - pointer to returned group or user name
+ *
+ * Returns:
+ *
+ * The return value is zero if no error occurs,
+ * A negative return value indicates an error.
+ */
+
+NSAPI_PUBLIC int nsadbIdToName(NSErr_t * errp,
+ void * authdb, USI_t id, int flags, char **rptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ void * whichdb = 0;
+ char * name;
+ int rv;
+
+ if (rptr != 0) *rptr = 0;
+
+ /* Decide whether to use user or group database */
+ if (flags & AIF_USER) {
+
+ whichdb = adb->adb_userdb;
+ if (whichdb == 0) {
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UREAD);
+ if (rv < 0) goto punt;
+ whichdb = adb->adb_userdb;
+ }
+ }
+ else if (flags & AIF_GROUP) {
+
+ whichdb = adb->adb_groupdb;
+ if (whichdb == 0) {
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GREAD);
+ if (rv < 0) goto punt;
+ whichdb = adb->adb_groupdb;
+ }
+ }
+
+ if (whichdb != 0) {
+
+ /* Get the name corresponding to the id */
+ rv = ndbIdToName(errp, whichdb, id, 0, &name);
+ if (rv < 0) goto punt;
+
+ if ((rptr != 0)) *rptr = name;
+ rv = 0;
+ }
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbFindByName)
+ *
+ * This function looks up a specified name in the authentication
+ * database. Flags specified by the caller indicate whether a
+ * group name, user name, or either should be found. The caller
+ * may optionally provide for the return of a user or group object
+ * pointer, in which case the information associated with a
+ * matching group or user is used to create a group or user object.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * name - name of group or user
+ * flags - search flags (defined in nsauth.h)
+ * rptr - pointer to returned group or user
+ * object pointer (may be null)
+ *
+ * Returns:
+ *
+ * The return value is a non-negative value if no error occurs,
+ * and the value indicates whether the name matched a group or
+ * user:
+ *
+ * AIF_NONE - name did not match a group or user name
+ * AIF_GROUP - name matched a group name
+ * AIF_USER - name matched a user name
+ *
+ * If the value is AIF_GROUP or AIF_USER, and rptr is non-null,
+ * then a group or user object is created, and a pointer to it is
+ * returned in the location indicated by rptr.
+ *
+ * A negative return value indicates an error.
+ */
+
+NSAPI_PUBLIC int nsadbFindByName(NSErr_t * errp, void * authdb,
+ char * name, int flags, void **rptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ ATR_t recptr;
+ int reclen;
+ int rv;
+
+ if (rptr != 0) *rptr = 0;
+
+ /* Search for group name? */
+ if (flags & AIF_GROUP) {
+
+ if (adb->adb_groupdb == 0) {
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GREAD);
+ if (rv < 0) goto punt;
+ }
+
+ /* Look up the name in the group database */
+ rv = ndbFindName(errp, adb->adb_groupdb, 0, (char *)name,
+ &reclen, (char **)&recptr);
+ if (rv == 0) {
+
+ /* Found it. Make a group object if requested. */
+ if (rptr != 0) {
+
+ /* Got the group record. Decode into a group object. */
+ *rptr = (void *)groupDecode((NTS_t)name, reclen, recptr);
+ }
+
+ return AIF_GROUP;
+ }
+ }
+
+ /* Search for user name? */
+ if (flags & AIF_USER) {
+
+ if (adb->adb_userdb == 0) {
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UREAD);
+ if (rv < 0) goto punt;
+ }
+
+ /* Look up the name in the user database */
+ rv = ndbFindName(errp, adb->adb_userdb, 0, (char *)name,
+ &reclen, (char **)&recptr);
+ if (rv == 0) {
+
+ /* Found it. Make a user object if requested. */
+ if (rptr != 0) {
+
+ /* Got the user record. Decode into a user object. */
+ *rptr = (void *)userDecode((NTS_t)name, reclen, recptr);
+ }
+
+ return AIF_USER;
+ }
+ }
+
+ /* Nothing found */
+ nserrDispose(errp);
+ return AIF_NONE;
+
+ punt:
+ return rv;
+}
diff --git a/lib/libaccess/nsamgmt.cpp b/lib/libaccess/nsamgmt.cpp
new file mode 100644
index 00000000..544d3617
--- /dev/null
+++ b/lib/libaccess/nsamgmt.cpp
@@ -0,0 +1,1567 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsamgmt.c)
+ *
+ * This module contains routines for managing information in a
+ * Netscape authentication database. An authentication database
+ * consists of a user database and a group database. This module
+ * implements an authentication database based on Netscape user and
+ * group databases defined in nsuser.h and nsgroup.h, which in turn
+ * are based on the Netscape (server) database implementation
+ * defined in nsdb.h. The interface for retrieving information
+ * from an authentication database is described separately in
+ * nsadb.h.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "base/file.h"
+#define __PRIVATE_NSADB
+#include "libaccess/nsamgmt.h"
+#include "libaccess/nsumgmt.h"
+#include "libaccess/nsgmgmt.h"
+
+/*
+ * Description (nsadbEnumUsersHelp)
+ *
+ * This is a local function that is called by NSDB during user
+ * database enumeration. It decodes user records into user
+ * objects, and presents them to the caller of nsadbEnumerateUsers(),
+ * via the specified call-back function. The call-back function
+ * return value may be a negative error code, which will cause
+ * enumeration to stop, and the error code will be returned from
+ * nsadbEnumerateUsers(). If the return value of the call-back
+ * function is not negative, it can contain one or more of the
+ * following flags:
+ *
+ * ADBF_KEEPOBJ - do not free the UserObj_t structure
+ * that was passed to the call-back function
+ * ADBF_STOPENUM - stop the enumeration without an error
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * parg - pointer to UserEnumArgs_t structure
+ * namelen - user record key length including null
+ * terminator
+ * name - user record key (user account name)
+ * reclen - length of user record
+ * recptr - pointer to user record contents
+ *
+ * Returns:
+ *
+ * If the call-back returns a negative result, that value is
+ * returned. If the call-back returns ADBF_STOPENUM, then
+ * -1 is returned, causing the enumeration to stop. Otherwise
+ * the return value is zero.
+ */
+
+typedef struct EnumUserArgs_s EnumUserArgs_t;
+struct EnumUserArgs_s {
+ void * authdb;
+ int (*func)(NSErr_t * ferrp,
+ void * authdb, void * argp, UserObj_t * uoptr);
+ void * user;
+ int rv;
+};
+
+static int nsadbEnumUsersHelp(NSErr_t * errp, void * parg,
+ int namelen, char * name,
+ int reclen, char * recptr)
+{
+ EnumUserArgs_t * ue = (EnumUserArgs_t *)parg;
+ UserObj_t * uoptr; /* user object pointer */
+ int rv;
+
+ uoptr = userDecode((NTS_t)name, reclen, (ATR_t)recptr);
+ if (uoptr != 0) {
+ rv = (*ue->func)(errp, ue->authdb, ue->user, uoptr);
+ if (rv >= 0) {
+
+ /* Count the number of users seen */
+ ue->rv += 1;
+
+ /* Free the user object unless the call-back says not to */
+ if (!(rv & ADBF_KEEPOBJ)) {
+ userFree(uoptr);
+ }
+ /* Return either 0 or -1, depending on ADBF_STOPENUM */
+ rv = (rv & ADBF_STOPENUM) ? -1 : 0;
+ }
+ else {
+ /* Free the user object in the event of an error */
+ userFree(uoptr);
+
+ /* Also return the error code */
+ ue->rv = rv;
+ }
+ }
+
+ return rv;
+}
+
+/*
+ * Description (nsadbEnumGroupsHelp)
+ *
+ * This is a local function that is called by NSDB during group
+ * database enumeration. It decodes group records into group
+ * objects, and presents them to the caller of nsadbEnumerateGroups(),
+ * via the specified call-back function. The call-back function
+ * return value may be a negative error code, which will cause
+ * enumeration to stop, and the error code will be returned from
+ * nsadbEnumerateGroups(). If the return value of the call-back
+ * function is not negative, it can contain one or more of the
+ * following flags:
+ *
+ * ADBF_KEEPOBJ - do not free the GroupObj_t structure
+ * that was passed to the call-back function
+ * ADBF_STOPENUM - stop the enumeration without an error
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * parg - pointer to GroupEnumArgs_t structure
+ * namelen - group record key length including null
+ * terminator
+ * name - group record key (group name)
+ * reclen - length of group record
+ * recptr - pointer to group record contents
+ *
+ * Returns:
+ *
+ * If the call-back returns a negative result, that value is
+ * returned. If the call-back returns ADBF_STOPENUM, then
+ * -1 is returned, causing the enumeration to stop. Otherwise
+ * the return value is zero.
+ */
+
+typedef struct EnumGroupArgs_s EnumGroupArgs_t;
+struct EnumGroupArgs_s {
+ void * authdb;
+ int (*func)(NSErr_t * ferrp,
+ void * authdb, void * argp, GroupObj_t * goptr);
+ void * user;
+ int rv;
+};
+
+static int nsadbEnumGroupsHelp(NSErr_t * errp, void * parg,
+ int namelen, char * name,
+ int reclen, char * recptr)
+{
+ EnumGroupArgs_t * eg = (EnumGroupArgs_t *)parg;
+ GroupObj_t * goptr; /* group object pointer */
+ int rv;
+
+ goptr = groupDecode((NTS_t)name, reclen, (ATR_t)recptr);
+ if (goptr != 0) {
+ rv = (*eg->func)(errp, eg->authdb, eg->user, goptr);
+ if (rv >= 0) {
+
+ /* Count the number of groups seen */
+ eg->rv += 1;
+
+ /* Free the group object unless the call-back says not to */
+ if (!(rv & ADBF_KEEPOBJ)) {
+ groupFree(goptr);
+ }
+ /* Return either 0 or -1, depending on ADBF_STOPENUM */
+ rv = (rv & ADBF_STOPENUM) ? -1 : 0;
+ }
+ else {
+ /* Free the group object in the event of an error */
+ groupFree(goptr);
+
+ /* Also return the error code */
+ eg->rv = rv;
+ }
+ }
+
+ return rv;
+}
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ * Description (nsadbAddGroupToGroup)
+ *
+ * This function adds a child group, C, to the definition of a
+ * parent group P. This involves updating the group entries of
+ * C and P in the group database. It also involves updating
+ * the group lists of any user descendants of C, to reflect the
+ * fact that these users are now members of P and P's ancestors.
+ * A check is made for an attempt to create a cycle in the group
+ * hierarchy, and this is rejected as an error.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * pgoptr - pointer to parent group object
+ * cgoptr - pointer to child group object
+ *
+ * Returns:
+ *
+ * The return value is zero if group C was not already a direct
+ * member of group P, and was added successfully. A return value
+ * of +1 indicates that group C was already a direct member of
+ * group P. A negative return value indicates an error.
+ */
+
+NSAPI_PUBLIC int nsadbAddGroupToGroup(NSErr_t * errp, void * authdb,
+ GroupObj_t * pgoptr, GroupObj_t * cgoptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ USIList_t gsuper; /* list of ancestors of group P */
+ USIList_t dglist; /* descendant groups of C */
+ GroupObj_t * dgoptr; /* descendant group object pointer */
+ UserObj_t * uoptr; /* user object pointer */
+ USI_t id; /* current descendant group id */
+ int usercount; /* count of users for descendant */
+ USI_t * userlist; /* pointer to array of descendant user ids */
+ USI_t * idlist; /* pointer to array of descendant group ids */
+ int pass; /* loop pass number */
+ int i; /* loop index */
+ int rv; /* result value */
+
+ /* Is C a direct member of P already? */
+ if (usiPresent(&pgoptr->go_groups, cgoptr->go_gid)) {
+ /* Yes, indicate that */
+ return 0;
+ }
+
+ dgoptr = 0;
+ uoptr = 0;
+
+ /* Initialize a list of the group descendants of group C */
+ UILINIT(&dglist);
+
+ /* Initialize a list of P and its ancestors */
+ UILINIT(&gsuper);
+
+ /* Add P to the ancestor list */
+ rv = usiInsert(&gsuper, pgoptr->go_gid);
+ if (rv < 0) goto punt;
+
+ /* Open user database since the group lists of users may be modified */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* Open group database since group entries will be modified */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ /* Merge all the ancestors of group P into the list */
+ rv = nsadbSuperGroups(errp, authdb, pgoptr, &gsuper);
+ if (rv < 0) goto punt;
+
+ /*
+ * Each pass through the following loop visits C and all of C's
+ * descendant groups.
+ *
+ * The first pass checks to see if making group C a member of
+ * group P would create a cycle in the group structure. It does
+ * this by examining C and all of its dependents to see if any
+ * appear in the list containing P and P's ancestors.
+ *
+ * The second pass updates the group lists of all users contained
+ * in group C to include P and P's ancestors.
+ */
+
+ for (pass = 1; pass < 3; ++pass) {
+
+ /* Use the group C as the first descendant */
+ id = cgoptr->go_gid;
+ dgoptr = cgoptr;
+
+ for (;;) {
+
+ if (pass == 1) {
+ /*
+ * Check for attempt to create a cycle in the group
+ * hierarchy. See if this descendant is a member of
+ * the list of P and P's ancestors (gsuper).
+ */
+ if (usiPresent(&gsuper, id)) {
+ /*
+ * Error - operation would create a cycle
+ * in the group structure.
+ */
+ return -1;
+ }
+ }
+ else {
+
+ /*
+ * Merge the list of ancestors of P (gsuper) with the
+ * group lists of any direct user members of the current
+ * descendant group, referenced by dgoptr.
+ */
+
+ /* Get direct user member list size and pointer */
+ usercount = UILCOUNT(&dgoptr->go_users);
+ userlist = UILLIST(&dgoptr->go_users);
+
+ /* For each direct user member of this descendant ... */
+ for (i = 0; i < usercount; ++i) {
+
+ /* Get a user object for the user */
+ uoptr = userFindByUid(errp,
+ adb->adb_userdb, userlist[i]);
+ if (uoptr == 0) {
+ /*
+ * Error - user not found,
+ * databases are inconsistent.
+ */
+ rv = -1;
+ goto punt;
+ }
+
+ /* Merge gsuper into the user's group list */
+ rv = uilMerge(&uoptr->uo_groups, &gsuper);
+ if (rv < 0) goto punt;
+
+ /* Write out the user object */
+ uoptr->uo_flags |= UOF_MODIFIED;
+ rv = userStore(errp, adb->adb_userdb, 0, uoptr);
+ if (rv) goto punt;
+
+ /* Free the user object */
+ userFree(uoptr);
+ uoptr = 0;
+ }
+ }
+
+ /*
+ * Merge the direct member groups of the current descendant
+ * group into the list of descendants to be processed.
+ */
+ rv = uilMerge(&dglist, &dgoptr->go_groups);
+ if (rv < 0) goto punt;
+
+ /* Free the group object for the current descendant */
+ if (dgoptr != cgoptr) {
+ groupFree(dgoptr);
+ dgoptr = 0;
+ }
+
+ /* Exit the loop if the descendant list is empty */
+ if (UILCOUNT(&dglist) <= 0) break;
+
+ /* Otherwise remove the next descendant from the list */
+ idlist = UILLIST(&dglist);
+ id = idlist[0];
+ rv = usiRemove(&dglist, id);
+ if (rv < 0) goto punt;
+
+ /* Now get a group object for this descendant group */
+ dgoptr = groupFindByGid(errp, adb->adb_groupdb, id);
+ if (dgoptr == 0) {
+ /* Error - group not found, databases are inconsistent */
+ rv = -1;
+ goto punt;
+ }
+ }
+ }
+
+ /* Now add C to P's list of member groups */
+ rv = usiInsert(&pgoptr->go_groups, cgoptr->go_gid);
+ if (rv < 0) goto punt;
+
+ /* Add P to C's list of parent groups */
+ rv = usiInsert(&cgoptr->go_pgroups, pgoptr->go_gid);
+ if (rv < 0) goto punt;
+
+ /* Update the database entry for group C */
+ cgoptr->go_flags |= GOF_MODIFIED;
+ rv = groupStore(errp, adb->adb_groupdb, 0, cgoptr);
+ if (rv) goto punt;
+
+ /* Update the database entry for group P */
+ pgoptr->go_flags |= GOF_MODIFIED;
+ rv = groupStore(errp, adb->adb_groupdb, 0, pgoptr);
+
+ return rv;
+
+ punt:
+ /* Handle errors */
+ UILFREE(&gsuper);
+ UILFREE(&dglist);
+ if (dgoptr) {
+ groupFree(dgoptr);
+ }
+ if (uoptr) {
+ userFree(uoptr);
+ }
+ return rv;
+}
+
+/*
+ * Description (nsadbAddUserToGroup)
+ *
+ * This function adds a user to a group definition. This involves
+ * updating the group entry in the group database, and the user
+ * entry in the user database. The caller provides a pointer to
+ * a user object for the user to be added, a pointer to a group
+ * object for the group being modified, and a handle for the
+ * authentication databases (from nsadbOpen()).
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * goptr - pointer to group object
+ * uoptr - pointer to user object
+ *
+ * Returns:
+ *
+ * The return value is zero if the user was not already a direct
+ * member of the group, and was added successfully. A return value
+ * of +1 indicates that the user was already a direct member of the
+ * group. A negative return value indicates an error.
+ */
+
+NSAPI_PUBLIC int nsadbAddUserToGroup(NSErr_t * errp, void * authdb,
+ GroupObj_t * goptr, UserObj_t * uoptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ USIList_t nglist; /* new group list for specified user */
+ USIList_t gsuper; /* groups containing+ the specified group */
+ GroupObj_t * aoptr; /* group object for 'id' group */
+ USI_t * idlist; /* pointer to gsuper gid array */
+ USI_t id; /* current gid from gsuper */
+ int rv; /* result value */
+
+ /* Is the user already a direct member of the group? */
+ if (usiPresent(&goptr->go_users, uoptr->uo_uid)) {
+
+ /* Yes, nothing to do */
+ return 1;
+ }
+
+ /*
+ * The user object contains a list of all of the groups that contain
+ * the user, either directly or indirectly. We need to add the
+ * specified group and its ancestors to this list. Each group contains
+ * a list of the group's parents, which is used to locate all of the
+ * group's ancestors. As an optimization, we need not consider any
+ * ancestors which are already on the user's current group list.
+ */
+
+ /*
+ * The following loop will deal with two lists of group ids. One
+ * is the list that will become the new group list for the user,
+ * which is initialized to the user's current group list. The other
+ * is a list of ancestors of the group to be considered for addition
+ * to the user's group list. This list is initialized to the specified
+ * group.
+ */
+
+ /* Initialize both lists to be empty */
+ UILINIT(&nglist);
+ UILINIT(&gsuper);
+
+ /* Make a copy of the user's current group list */
+ rv = uilDuplicate(&nglist, &uoptr->uo_groups);
+ if (rv < 0) goto punt;
+
+ /* Start the other list with the specified group */
+ rv = usiInsert(&gsuper, goptr->go_gid);
+ if (rv < 0) goto punt;
+
+ /* Open user database since the group lists of users may be modified */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* Open group database since group entries will be modified */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ /* While entries remain on the ancestor list */
+ while (UILCOUNT(&gsuper) > 0) {
+
+ /* Get pointer to array of ancestor group ids */
+ idlist = UILLIST(&gsuper);
+
+ /* Remove the first ancestor */
+ id = idlist[0];
+ usiRemove(&gsuper, id);
+
+ /* Is the ancestor on the user's current group list? */
+ if (!usiPresent(&uoptr->uo_groups, id)) {
+
+ /* No, add its parents to the ancestor list */
+
+ /* Look up the ancestor group (get a group object for it) */
+ aoptr = groupFindByGid(errp, adb->adb_groupdb, id);
+ if (aoptr == 0) {
+ /* Error - group not found, database inconsistent */
+ rv = -1;
+ goto punt;
+ }
+
+ /* Merge the ancestors parents into the ancestor list */
+ rv = uilMerge(&gsuper, &aoptr->go_pgroups);
+
+ /* Lose the ancestor group object */
+ groupFree(aoptr);
+
+ /* See if the merge worked */
+ if (rv < 0) goto punt;
+ }
+
+ /* Add the ancestor to the new group list for the user */
+ rv = usiInsert(&nglist, id);
+ if (rv < 0) goto punt;
+ }
+
+ /* Add the user to the group's user member list */
+ rv = usiInsert(&goptr->go_users, uoptr->uo_uid);
+ if (rv < 0) goto punt;
+
+ /* Replace the user's group list with the new one */
+ UILREPLACE(&uoptr->uo_groups, &nglist);
+
+ /* Write out the updated user object */
+ uoptr->uo_flags |= UOF_MODIFIED;
+ rv = userStore(errp, adb->adb_userdb, 0, uoptr);
+ if (rv < 0) goto punt;
+
+ /* Write out the updated group object */
+ goptr->go_flags |= GOF_MODIFIED;
+ rv = groupStore(errp, adb->adb_groupdb, 0, goptr);
+
+ return rv;
+
+ punt:
+ /* Handle error */
+
+ /* Free ancestor and new group lists */
+ UILFREE(&nglist);
+ UILFREE(&gsuper);
+
+ return rv;
+}
+
+/*
+ * Description (nsadbCreateGroup)
+ *
+ * This function creates a new group in a specified authentication
+ * database. The group is described by a group object. A group
+ * object can be created by calling nsadbGroupNew().
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * goptr - pointer to group object
+ *
+ * Returns:
+ */
+
+NSAPI_PUBLIC int nsadbCreateGroup(NSErr_t * errp, void * authdb, GroupObj_t * goptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ int rv;
+
+ /* Open the group database for write access */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ /* Add this group to the database */
+ rv = groupStore(errp, adb->adb_groupdb, 0, goptr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbCreateUser)
+ *
+ * This function creates a new user in a specified authentication
+ * database. The user is described by a user object. A user
+ * object can be created by calling nsadbUserNew().
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * uoptr - pointer to user object
+ *
+ * Returns:
+ */
+
+NSAPI_PUBLIC int nsadbCreateUser(NSErr_t * errp, void * authdb, UserObj_t * uoptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ int rv;
+
+ /* Open the user database for write access */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* Add this user to the database */
+ rv = userStore(errp, adb->adb_userdb, 0, uoptr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbEnumerateUsers)
+ *
+ * This function is called to enumerate all of the users in a
+ * given authentication database to a call-back function specified
+ * by the caller. The call-back function is provided with a
+ * handle for the authentication database, an opaque value provided
+ * by the caller, and a pointer to a user object. See the
+ * description of nsadbEnumUsersHelp above for the interpretation
+ * of the call-back function's return value.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * argp - opaque value for call-back function
+ * func - pointer to call-back function
+ *
+ * Returns:
+ *
+ * If the call-back function returns a negative error code, this
+ * value is returned. A negative value may also be returned if
+ * nsadb encounters an error. Otherwise the result is the number
+ * of users enumerated.
+ */
+
+NSAPI_PUBLIC int nsadbEnumerateUsers(NSErr_t * errp, void * authdb, void * argp,
+#ifdef UnixWare
+ ArgFn_EnumUsers func) /* for ANSI C++ standard, see nsamgmt.h */
+#else
+ int (*func)(NSErr_t * ferrp, void * authdb, void * parg, UserObj_t * uoptr))
+#endif
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ EnumUserArgs_t args; /* arguments for enumeration helper */
+ int rv; /* result value */
+
+ /* Open the users subdatabase for read access */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UREAD);
+ if (rv < 0) goto punt;
+
+ args.authdb = authdb;
+ args.func = func;
+ args.user = argp;
+ args.rv = 0;
+
+ rv = ndbEnumerate(errp, adb->adb_userdb,
+ NDBF_ENUMNORM, (void *)&args, nsadbEnumUsersHelp);
+ if (rv < 0) goto punt;
+
+ rv = args.rv;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbEnumerateGroups)
+ *
+ * This function is called to enumerate all of the groups in a
+ * given authentication database to a call-back function specified
+ * by the caller. The call-back function is provided with a
+ * handle for the authentication database, an opaque value provided
+ * by the caller, and a pointer to a group object. See the
+ * description of nsadbEnumGroupsHelp above for the interpretation
+ * of the call-back function's return value.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * argp - opaque value for call-back function
+ * func - pointer to call-back function
+ *
+ * Returns:
+ *
+ * If the call-back function returns a negative error code, this
+ * value is returned. A negative value may also be returned if
+ * nsadb encounters an error. Otherwise the result is the number
+ * of groups enumerated.
+ */
+
+NSAPI_PUBLIC int nsadbEnumerateGroups(NSErr_t * errp, void * authdb, void * argp,
+#ifdef UnixWare
+ ArgFn_EnumGroups func) /* for ANSI C++ standard, see nsamgmt.h */
+#else
+ int (*func)(NSErr_t * ferrp, void * authdb, void * parg, GroupObj_t * goptr))
+#endif
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ EnumGroupArgs_t args;
+ int rv; /* result value */
+
+ /* Open group database for read access */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GREAD);
+ if (rv < 0) goto punt;
+
+ args.authdb = authdb;
+ args.func = func;
+ args.user = argp;
+ args.rv = 0;
+
+ rv = ndbEnumerate(errp, adb->adb_groupdb,
+ NDBF_ENUMNORM, (void *)&args, nsadbEnumGroupsHelp);
+ if (rv < 0) goto punt;
+
+ rv = args.rv;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbIsUserInGroup)
+ *
+ * This function tests whether a given user id is a member of the
+ * group associated with a specified group id. The caller may
+ * provide a list of group ids for groups to which the user is
+ * already known to belong, and this may speed up the check.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * uid - user id
+ * gid - group id
+ * ngroups - number of group ids in grplist
+ * grplist - groups the user is known to belong to
+ *
+ * Returns:
+ *
+ * The return value is +1 if the user is found to belong to the
+ * indicated group, or 0 if the user does not belong to the group.
+ * An error is indicated by a negative return value.
+ */
+
+NSAPI_PUBLIC int nsadbIsUserInGroup(NSErr_t * errp, void * authdb,
+ USI_t uid, USI_t gid, int ngroups, USI_t * grplist)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ USIList_t dglist; /* descendant group list */
+ GroupObj_t * goptr = 0; /* group object pointer */
+ USI_t * idlist; /* pointer to array of group ids */
+ USI_t tgid; /* test group id */
+ int i; /* loop index */
+ int rv; /* result value */
+
+ UILINIT(&dglist);
+
+ /* Open group database for read access */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GREAD);
+ if (rv < 0) goto punt;
+
+ for (tgid = gid;;) {
+
+ /* Get a group object for this group id */
+ goptr = groupFindByGid(errp, adb->adb_groupdb, tgid);
+ if (goptr == 0) {
+ /* Error - group id not found, databases are inconsistent */
+ rv = -1;
+ goto punt;
+ }
+
+ /* Is the user a direct member of this group? */
+ if (usiPresent(&goptr->go_users, uid)) goto is_member;
+
+ /*
+ * Is there any group to which the user is already known to
+ * belong that is a direct group member of this group? If so,
+ * the user is also a member of this group.
+ */
+
+ /* Scan list of groups to which the user is known to belong */
+ for (i = 0; i < ngroups; ++i) {
+
+ if (usiPresent(&goptr->go_groups, grplist[i])) goto is_member;
+ }
+
+ /* Merge group member list of this group with descendants list */
+ rv = uilMerge(&dglist, &goptr->go_groups);
+ if (rv < 0) goto punt;
+
+ /*
+ * If descendants list is empty, the user is not contained in
+ * the specified group.
+ */
+ if (UILCOUNT(&dglist) <= 0) {
+ rv = 0;
+ goto punt;
+ }
+
+ /* Remove the next id from the descendants list */
+ idlist = UILLIST(&dglist);
+ tgid = idlist[0];
+
+ rv = usiRemove(&dglist, tgid);
+ if (rv < 0) goto punt;
+
+ groupFree(goptr);
+ goptr = 0;
+ }
+
+ is_member:
+ rv = 1;
+
+ punt:
+ if (goptr) {
+ groupFree(goptr);
+ }
+ UILFREE(&dglist);
+ return rv;
+}
+
+/*
+ * Description (nsadbModifyGroup)
+ *
+ * This function is called to write modifications to a group to
+ * a specified authentication database. The group is assumed to
+ * already exist in the database. Information about the group
+ * is passed in a group object. This function should not be used
+ * to alter the lists of group members or parents.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * goptr - pointer to modified group object
+ *
+ * Returns:
+ *
+ * The return value is zero if the group information is successfully
+ * updated. An error is indicated by a negative return value, and
+ * an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbModifyGroup(NSErr_t * errp, void * authdb, GroupObj_t * goptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ int rv;
+
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ rv = groupStore(errp, adb->adb_groupdb, 0, goptr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbModifyUser)
+ *
+ * This function is called to write modifications to a user to
+ * a specified authentication database. The user is assumed to
+ * already exist in the database. Information about the user
+ * is passed in a user object. This function should not be used
+ * to modify the list of groups which contain the user.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * uoptr - pointer to modified user object
+ *
+ * Returns:
+ *
+ * The return value is zero if the user information is successfully
+ * updated. An error is indicated by a negative return value, and
+ * an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbModifyUser(NSErr_t * errp, void * authdb, UserObj_t * uoptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ int rv;
+
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ rv = userStore(errp, adb->adb_userdb, 0, uoptr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbRemoveGroup)
+ *
+ * This function is called to remove a given group name from
+ * a specified authentication database. This can cause updates
+ * to both the user and group subdatabases.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * name - pointer to name of group to remove
+ *
+ * Returns:
+ *
+ * The return value is zero if the group information is successfully
+ * removed. An error is indicated by a negative return value, and
+ * an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbRemoveGroup(NSErr_t * errp, void * authdb, char * name)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ UserObj_t * uoptr = 0; /* user object pointer */
+ GroupObj_t * goptr = 0; /* group object pointer */
+ GroupObj_t * ogoptr = 0; /* other group object pointer */
+ char * ugname; /* user or group name */
+ USI_t * list; /* pointer into user/group id list */
+ int cnt; /* count of user or group ids */
+ int i; /* loop index */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Open the groups subdatabase for write access */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ /* Look up the group to be removed, and get a group object */
+ rv = nsadbFindByName(errp, authdb, name, AIF_GROUP, (void **)&goptr);
+ if (rv != AIF_GROUP) {
+ if (rv < 0) goto punt;
+ goto err_nogroup;
+ }
+
+ /* Mark the group for delete */
+ goptr->go_flags |= GOF_DELPEND;
+
+ /* Does the specified group belong to any groups? */
+ cnt = UILCOUNT(&goptr->go_pgroups);
+ if (cnt > 0) {
+
+ /* Yes, for each parent group ... */
+ for (i = 0; i < cnt; ++i) {
+
+ /* Note that nsadbRemGroupFromGroup() will shrink this list */
+ list = UILLIST(&goptr->go_pgroups);
+
+ /* Get group name associated with the group id */
+ rv = nsadbIdToName(errp, authdb, *list, AIF_GROUP, &ugname);
+ if (rv < 0) goto punt;
+
+ /* Look up the group by name and get a group object for it */
+ rv = nsadbFindByName(errp,
+ authdb, ugname, AIF_GROUP, (void **)&ogoptr);
+ if (rv < 0) goto punt;
+
+ /* Remove the specified group from the parent group */
+ rv = nsadbRemGroupFromGroup(errp, authdb, ogoptr, goptr);
+ if (rv < 0) goto punt;
+
+ /* Free the parent group object */
+ groupFree(ogoptr);
+ ogoptr = 0;
+ }
+ }
+
+ /* Are there any group members of this group? */
+ cnt = UILCOUNT(&goptr->go_groups);
+ if (cnt > 0) {
+
+ /* For each group member of the group ... */
+
+ for (i = 0; i < cnt; ++i) {
+
+ /* Note that nsadbRemGroupFromGroup() will shrink this list */
+ list = UILLIST(&goptr->go_groups);
+
+ /* Get group name associated with the group id */
+ rv = nsadbIdToName(errp, authdb, *list, AIF_GROUP, &ugname);
+ if (rv < 0) goto punt;
+
+ /* Look up the group by name and get a group object for it */
+ rv = nsadbFindByName(errp,
+ authdb, ugname, AIF_GROUP, (void **)&ogoptr);
+ if (rv < 0) goto punt;
+
+ /* Remove member group from the specified group */
+ rv = nsadbRemGroupFromGroup(errp, authdb, goptr, ogoptr);
+ if (rv < 0) goto punt;
+
+ /* Free the member group object */
+ groupFree(ogoptr);
+ ogoptr = 0;
+ }
+ }
+
+ /* Are there any direct user members of this group? */
+ cnt = UILCOUNT(&goptr->go_users);
+ if (cnt > 0) {
+
+ /* Yes, open users subdatabase for write access */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* For each user member of the group ... */
+ for (i = 0; i < cnt; ++i) {
+
+ /* Note that nsadbRemUserFromGroup() will shrink this list */
+ list = UILLIST(&goptr->go_users);
+
+ /* Get user name associated with the user id */
+ rv = nsadbIdToName(errp, authdb, *list, AIF_USER, &ugname);
+ if (rv < 0) goto punt;
+
+ /* Look up the user by name and get a user object for it */
+ rv = nsadbFindByName(errp,
+ authdb, ugname, AIF_USER, (void **)&uoptr);
+ if (rv < 0) goto punt;
+
+ /* Remove user from the group */
+ rv = nsadbRemUserFromGroup(errp, authdb, goptr, uoptr);
+ if (rv < 0) goto punt;
+
+ /* Free the member user object */
+ userFree(uoptr);
+ uoptr = 0;
+ }
+ }
+
+ /* Free the group object for the specified group */
+ groupFree(goptr);
+ goptr = 0;
+
+ /* Now we can remove the group entry */
+ rv = groupRemove(errp, adb->adb_groupdb, 0, (NTS_t)name);
+
+ return rv;
+
+ err_nogroup:
+ eid = NSAUERR4100;
+ rv = NSAERRNAME;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 2, adb->adb_dbname, name);
+ goto punt;
+
+ punt:
+ /* Free any user or group objects that we created */
+ if (ogoptr != 0) {
+ groupFree(ogoptr);
+ }
+ if (uoptr != 0) {
+ userFree(uoptr);
+ }
+ if (goptr != 0) {
+ groupFree(goptr);
+ }
+ return rv;
+}
+
+/*
+ * Description (nsadbRemoveUser)
+ *
+ * This function is called to remove a given user name from
+ * a specified authentication database. This can cause updates
+ * to both the user and user subdatabases.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * name - pointer to name of user to remove
+ *
+ * Returns:
+ *
+ * The return value is zero if the user information is successfully
+ * removed. An error is indicated by a negative return value, and
+ * an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbRemoveUser(NSErr_t * errp, void * authdb, char * name)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ UserObj_t * uoptr = 0; /* user object pointer */
+ GroupObj_t * goptr = 0; /* group object pointer */
+ char * gname; /* group name */
+ USI_t * list; /* pointer into group id list */
+ int gcnt; /* number of groups containing user */
+ int i; /* loop index */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Open the users subdatabase for write access */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* Look up the user to be removed, and get a user object */
+ rv = nsadbFindByName(errp, authdb, name, AIF_USER, (void **)&uoptr);
+ if (rv != AIF_USER) {
+ if (rv < 0) goto punt;
+ goto err_nouser;
+ }
+
+ /* Mark the user for delete */
+ uoptr->uo_flags |= UOF_DELPEND;
+
+ /* Does this user belong to any groups? */
+ gcnt = UILCOUNT(&uoptr->uo_groups);
+ if (gcnt > 0) {
+
+ /* Yes, get pointer to list of group ids */
+ list = UILLIST(&uoptr->uo_groups);
+
+ /* Open groups subdatabase for write access */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ /* For each group that the user belongs to ... */
+ for (i = 0; i < gcnt; ++i) {
+
+ /* Get group name associated with the group id */
+ rv = nsadbIdToName(errp, authdb, *list, AIF_GROUP, &gname);
+ if (rv < 0) goto punt;
+
+ /* Look up the group by name and get a group object for it */
+ rv = nsadbFindByName(errp,
+ authdb, gname, AIF_GROUP, (void **)&goptr);
+ if (rv < 0) goto punt;
+
+ /* Remove user from group if it's a direct member */
+ rv = nsadbRemUserFromGroup(errp, authdb, goptr, uoptr);
+ if (rv < 0) goto punt;
+
+ /* Free the group object */
+ groupFree(goptr);
+ goptr = 0;
+
+ ++list;
+ }
+ }
+
+#ifdef CLIENT_AUTH
+ /* Remove certificate mapping for user, if any */
+ rv = nsadbRemoveUserCert(errp, authdb, name);
+#endif
+
+ /* Free the user object */
+ userFree(uoptr);
+
+ /* Now we can remove the user entry */
+ rv = userRemove(errp, adb->adb_userdb, 0, (NTS_t)name);
+
+ return rv;
+
+ err_nouser:
+ eid = NSAUERR4000;
+ rv = NSAERRNAME;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 2, adb->adb_dbname, name);
+ goto punt;
+
+ punt:
+ if (goptr != 0) {
+ groupFree(goptr);
+ }
+ if (uoptr != 0) {
+ userFree(uoptr);
+ }
+ return rv;
+}
+
+/*
+ * Description (nsadbRemGroupFromGroup)
+ *
+ * This function removes a given group C from a parent group P.
+ * The group C must be a direct member of the group P. However,
+ * group C may also be a member of one or more of P's ancestor or
+ * descendant groups, and this function deals with that. The
+ * group entries for C and P are updated in the group database.
+ * But the real work is updating the groups lists of all of the
+ * users contained in C.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * pgoptr - pointer to parent group object
+ * cgoptr - pointer to child group object
+ *
+ * Returns:
+ *
+ * The return value is zero if group C was a direct member of
+ * group P, and was removed successfully. A return value of +1
+ * indicates that group C was not a direct member of the group P.
+ * A negative return value indicates an error.
+ */
+
+NSAPI_PUBLIC int nsadbRemGroupFromGroup(NSErr_t * errp, void * authdb,
+ GroupObj_t * pgoptr, GroupObj_t * cgoptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ USIList_t dglist; /* list of descendant groups of C */
+ GroupObj_t * dgoptr; /* descendant group object pointer */
+ UserObj_t * uoptr; /* user object pointer */
+ USI_t * gidlist; /* pointer to group id array */
+ USI_t * userlist; /* pointer to array of descendant user ids */
+ USI_t dgid; /* descendant group id */
+ int iusr; /* index on descendant user list */
+ int usercnt; /* count of descendant users */
+ int igrp; /* index of group in user group id list */
+ int rv; /* result value */
+
+ dgoptr = 0;
+ uoptr = 0;
+
+ /* Initialize a list of descendant groups of C */
+ UILINIT(&dglist);
+
+ /* Is group C a direct member of group P? */
+ if (!usiPresent(&pgoptr->go_groups, cgoptr->go_gid)) {
+
+ /* No, nothing to do */
+ return 1;
+ }
+
+ /* Remove group C from group P's group member list */
+ rv = usiRemove(&pgoptr->go_groups, cgoptr->go_gid);
+ if (rv < 0) goto punt;
+
+ /* Remove group P from group C's parent group list */
+ rv = usiRemove(&cgoptr->go_pgroups, pgoptr->go_gid);
+ if (rv < 0) goto punt;
+
+ /* Open user database since the group lists of users may be modified */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* Open group database since group entries will be modified */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ /* Write out the updated group C object */
+ cgoptr->go_flags |= GOF_MODIFIED;
+ rv = groupStore(errp, adb->adb_groupdb, 0, cgoptr);
+ if (rv) goto punt;
+
+ /* Write out the updated group P object */
+ pgoptr->go_flags |= GOF_MODIFIED;
+ rv = groupStore(errp, adb->adb_groupdb, 0, pgoptr);
+ if (rv) goto punt;
+
+ /* Now check the group lists of all users contained in group C */
+ dgoptr = cgoptr;
+ dgid = cgoptr->go_gid;
+
+ for (;;) {
+
+ /* Scan the direct user members of this descendant group */
+ usercnt = UILCOUNT(&dgoptr->go_users);
+ userlist = UILLIST(&dgoptr->go_users);
+
+ for (iusr = 0; iusr < usercnt; ++iusr) {
+
+ /* Get a user object for this user member */
+ uoptr = userFindByUid(errp, adb->adb_userdb, userlist[iusr]);
+ if (uoptr == 0) {
+ /* Error - user id not found, databases are inconsistent */
+ rv = -1;
+ goto punt;
+ }
+
+ /* Scan the group list for this user */
+ for (igrp = 0; igrp < UILCOUNT(&uoptr->uo_groups); ) {
+
+ gidlist = UILLIST(&uoptr->uo_groups);
+
+ /* Is the user a member of this group? */
+ if (nsadbIsUserInGroup(errp, authdb,
+ uoptr->uo_uid, gidlist[igrp],
+ igrp, gidlist)) {
+
+ /* Yes, step to next group id */
+ ++igrp;
+ }
+ else {
+ /*
+ * No, remove it from the user's list of groups. The
+ * next group id to consider will be shifted into the
+ * igrp position when the current id is removed.
+ */
+ rv = usiRemove(&uoptr->uo_groups, gidlist[igrp]);
+ if (rv < 0) goto punt;
+ uoptr->uo_flags |= UOF_MODIFIED;
+ }
+ }
+
+ /* Write out the user object if it was changed */
+ if (uoptr->uo_flags & UOF_MODIFIED) {
+ rv = userStore(errp, adb->adb_userdb, 0, uoptr);
+ if (rv < 0) goto punt;
+ }
+
+ /* Free the user object */
+ userFree(uoptr);
+ uoptr = 0;
+ }
+
+ /*
+ * Merge the direct member groups of this group into the
+ * descendants list.
+ */
+ rv = uilMerge(&dglist, &dgoptr->go_groups);
+ if (rv < 0) goto punt;
+
+ /* Free this descendant group object */
+ if (dgoptr != cgoptr) {
+ groupFree(dgoptr);
+ dgoptr = 0;
+ }
+
+ /* If the descendants list is empty, we're done */
+ if (UILCOUNT(&dglist) <= 0) break;
+
+ /* Remove the next group id from the descendants list */
+ gidlist = UILLIST(&dglist);
+ dgid = gidlist[0];
+ rv = usiRemove(&dglist, dgid);
+ if (rv < 0) goto punt;
+
+ /* Get a group object for this descendant group */
+ dgoptr = groupFindByGid(errp, adb->adb_groupdb, dgid);
+ if (dgoptr == 0) {
+ /* Error - group id not found, databases are inconsistent */
+ rv = -1;
+ goto punt;
+ }
+ }
+
+ UILFREE(&dglist);
+ return 0;
+
+ punt:
+ if (dgoptr) {
+ groupFree(dgoptr);
+ }
+ if (uoptr) {
+ userFree(uoptr);
+ }
+ UILFREE(&dglist);
+ return rv;
+}
+
+/*
+ * Description (nsadbRemUserFromGroup)
+ *
+ * This function removes a given user from a specified group G.
+ * The user must be a direct member of the group. However, the
+ * user may also be a member of one or more of G's descendant
+ * groups, and this function deals with that. The group entry
+ * for G is updated in the group database, with the user removed
+ * from its user member list. The user entry is updated in the
+ * user database, with an updated list of all groups which now
+ * contain the user.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * goptr - pointer to group object
+ * uoptr - pointer to user object
+ *
+ * Returns:
+ *
+ * The return value is zero if the user was a direct member of the
+ * group, and was removed successfully. A return value of +1
+ * indicates that the user was not a direct member of the
+ * group. A negative return value indicates an error.
+ */
+
+NSAPI_PUBLIC int nsadbRemUserFromGroup(NSErr_t * errp, void * authdb,
+ GroupObj_t * goptr, UserObj_t * uoptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ USI_t * idlist; /* pointer to user group id array */
+ USI_t tgid; /* test group id */
+ int igrp; /* position in user group list */
+ int rv; /* result value */
+
+ /* Is the user a direct member of the group? */
+ if (!usiPresent(&goptr->go_users, uoptr->uo_uid)) {
+
+ /* No, nothing to do */
+ return 1;
+ }
+
+ /* Remove the user from the group's user member list */
+ rv = usiRemove(&goptr->go_users, uoptr->uo_uid);
+ if (rv < 0) goto punt;
+
+ /* If the user object is pending deletion, no need to open databases */
+ if (!(uoptr->uo_flags & UOF_DELPEND)) {
+
+ /*
+ * Open user database since the group list of the user
+ * will be modified.
+ */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* Open group database since group entries will be modified */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+ }
+
+ /*
+ * Write out the updated group object. This must be done here
+ * because nsadbIsUserInGroup() in the loop below will read the
+ * entry for this group, and it needs to reflect the user's
+ * removal from being a direct member of the group. This does
+ * not preclude the possibility that the user will still be an
+ * indirect member of this group.
+ */
+ goptr->go_flags |= GOF_MODIFIED;
+ rv = groupStore(errp, adb->adb_groupdb, 0, goptr);
+ if (rv) goto punt;
+
+ /* If a delete is pending on the user, we're done */
+ if (uoptr->uo_flags & UOF_DELPEND) goto punt;
+
+ /*
+ * Begin loop to check whether user is still a member of each
+ * of the groups in its group list. Note that the group list
+ * may shrink during an iteration of the loop.
+ */
+
+ for (igrp = 0; igrp < UILCOUNT(&uoptr->uo_groups); ) {
+
+ /* Get pointer to the user's array of group ids */
+ idlist = UILLIST(&uoptr->uo_groups);
+
+ /* Get the group id of the next group to consider */
+ tgid = idlist[igrp];
+
+ /* Is the user a member of this group? */
+ if (nsadbIsUserInGroup(errp, authdb,
+ uoptr->uo_uid, tgid, igrp, idlist)) {
+
+ /* Yes, step to next group id */
+ ++igrp;
+ }
+ else {
+
+ /*
+ * No, remove it from the user's list of groups. The
+ * next group id to consider will be shifted into the
+ * igrp position when the current id is removed.
+ */
+ rv = usiRemove(&uoptr->uo_groups, tgid);
+ if (rv < 0) goto punt;
+ }
+ }
+
+ /* Write out the updated user object */
+ uoptr->uo_flags |= UOF_MODIFIED;
+ rv = userStore(errp, adb->adb_userdb, 0, uoptr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbSuperGroups)
+ *
+ * This function builds a list of the group ids for all groups
+ * which contain, directly or indirectly, a specified group as
+ * a subgroup. We call these the supergroups of the specified
+ * group.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * goptr - pointer to group object
+ * gsuper - pointer to list to contain supergroups
+ * (caller must initialize)
+ *
+ * Returns:
+ *
+ * Returns the number of elements in gsuper if successful. An
+ * error is indicated by a negative return value.
+ */
+
+NSAPI_PUBLIC int nsadbSuperGroups(NSErr_t * errp, void * authdb,
+ GroupObj_t * goptr, USIList_t * gsuper)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ USIList_t aglist; /* ancestor group id list */
+ GroupObj_t * aoptr; /* ancestor group object pointer */
+ USI_t * idlist; /* pointer to array of group ids */
+ USI_t id; /* current group id */
+ int rv; /* result value */
+
+ /* Initialize an empty ancestor group list */
+ UILINIT(&aglist);
+
+ /* Enter loop with specified group as first ancestor */
+ id = goptr->go_gid;
+ aoptr = goptr;
+
+ /* Open group database for read access */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GREAD);
+ if (rv < 0) goto punt;
+
+ /* Loop until the ancestor list is empty */
+ for (;;) {
+
+ /* Merge parent groups of current ancestor into ancestor list */
+ rv = uilMerge(&aglist, &aoptr->go_pgroups);
+ if (rv < 0) goto punt;
+
+ /* Also merge parent groups into the result list */
+ rv = uilMerge(gsuper, &aoptr->go_pgroups);
+ if (rv < 0) goto punt;
+
+ /* Free the ancestor group object (but not the original) */
+ if (aoptr != goptr) {
+ groupFree(aoptr);
+ aoptr = 0;
+ }
+
+ /* Exit the loop if the ancestor list is empty */
+ if (UILCOUNT(&aglist) <= 0) break;
+
+ /* Get pointer to array of ancestor group ids */
+ idlist = UILLIST(&aglist);
+
+ /* Remove the first ancestor */
+ id = idlist[0];
+ rv = usiRemove(&aglist, id);
+
+ /* Get a group object for the ancestor */
+ aoptr = groupFindByGid(errp, adb->adb_groupdb, id);
+ if (aoptr == 0) {
+ /* Error - group not found, database inconsistent */
+ rv = -1;
+ goto punt;
+ }
+ }
+
+ return UILCOUNT(gsuper);
+
+ punt:
+ /* Handle error */
+
+ /* Free ancestor list */
+ UILFREE(&aglist);
+
+ return rv;
+}
+
+NSPR_END_EXTERN_C
+
diff --git a/lib/libaccess/nsautherr.cpp b/lib/libaccess/nsautherr.cpp
new file mode 100644
index 00000000..308c0698
--- /dev/null
+++ b/lib/libaccess/nsautherr.cpp
@@ -0,0 +1,126 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsautherr.c)
+ *
+ * This module provides facilities for handling authentication
+ * errors.
+ */
+
+#include <string.h>
+#include "base/systems.h"
+#include "prprf.h"
+#include "libaccess/nserror.h"
+#include "libaccess/nsautherr.h"
+
+/* Error message formats XXX internationalize XXX */
+static char * nsaerrnomem = "insufficient dynamic memory";
+static char * nsaerrinval = "invalid argument";
+static char * nsaerropen = "error opening %s";
+static char * nsaerrmkdir = "error creating %s";
+static char * nsaerrname = "%s not found in database %s";
+static char * unknownerr = "error code %d";
+
+/*
+ * Description (nsadbErrorFmt)
+ *
+ * This function formats an authentication error message into a
+ * buffer provided by the caller. The authentication error
+ * information is passed in an error list structure. The caller
+ * can indicate how many error frames should be processed. A
+ * newline is inserted between messages for different error frames.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer
+ * msgbuf - pointer to error message buffer
+ * maxlen - maximum length of generated message
+ * maxdepth - maximum depth for traceback
+ */
+
+NSAPI_PUBLIC void nsadbErrorFmt(NSErr_t * errp, char * msgbuf, int maxlen, int maxdepth)
+{
+ NSEFrame_t * efp; /* error frame pointer */
+ int len; /* length of error message text */
+ int depth = 0; /* current depth */
+
+ msgbuf[0] = 0;
+
+ for (efp = errp->err_first; efp != 0; efp = efp->ef_next) {
+
+ /* Stop if the message buffer is full */
+ if (maxlen <= 0) break;
+
+ if (depth > 0) {
+ /* Put a newline between error frame messages */
+ *msgbuf++ = '\n';
+ if (--maxlen <= 0) break;
+ }
+
+ /* Identify the facility generating the error and the id number */
+ len = PR_snprintf(msgbuf, maxlen,
+ "[%s%d] ", efp->ef_program, efp->ef_errorid);
+ msgbuf += len;
+ maxlen -= len;
+
+ if (maxlen <= 0) break;
+
+ len = 0;
+
+ if (!strcmp(efp->ef_program, NSAuth_Program)) {
+
+ switch (efp->ef_retcode) {
+ case NSAERRNOMEM:
+ strncpy(msgbuf, nsaerrnomem, maxlen);
+ len = strlen(nsaerrnomem);
+ break;
+
+ case NSAERRINVAL:
+ /* Invalid function argument error: */
+ strncpy(msgbuf, nsaerrinval, maxlen);
+ len = strlen(nsaerrinval);
+ break;
+
+ case NSAERROPEN:
+ /* File open error: filename */
+ if (efp->ef_errc == 1) {
+ len = PR_snprintf(msgbuf, maxlen, nsaerropen,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ break;
+
+ case NSAERRMKDIR:
+ /* error creating database directory: database name */
+ if (efp->ef_errc == 1) {
+ len = PR_snprintf(msgbuf, maxlen, nsaerrmkdir,
+ efp->ef_errv[0]);
+ }
+ break;
+
+ case NSAERRNAME:
+ /* user or group name not found: database, name */
+ if (efp->ef_errc == 2) {
+ len = PR_snprintf(msgbuf, maxlen, nsaerrname,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ break;
+
+ default:
+ len = PR_snprintf(msgbuf, maxlen, unknownerr, efp->ef_retcode);
+ break;
+ }
+ }
+ else {
+ len = PR_snprintf(msgbuf, maxlen, unknownerr, efp->ef_retcode);
+ }
+
+ msgbuf += len;
+ maxlen -= len;
+
+ if (++depth >= maxdepth) break;
+ }
+}
diff --git a/lib/libaccess/nscert.cpp b/lib/libaccess/nscert.cpp
new file mode 100644
index 00000000..97939b24
--- /dev/null
+++ b/lib/libaccess/nscert.cpp
@@ -0,0 +1,963 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Description (nsadb.c)
+ *
+ * This module contains routines for accessing and storing information
+ * in a Netscape client certificate to username database. This
+ * database is used to associate a username with a client certificate
+ * that is presented to a server.
+ */
+
+#if defined(CLIENT_AUTH)
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <base/systems.h>
+#include <netsite.h>
+#include <base/file.h>
+#include <base/fsmutex.h>
+#include <libaccess/nsdbmgmt.h>
+#define __PRIVATE_NSADB
+#include <libaccess/nsadb.h>
+#include <libaccess/nsamgmt.h>
+
+static FSMUTEX nscert_lock = 0;
+
+NSAPI_PUBLIC int nsadbCertInitialize(void)
+{
+#ifdef XP_UNIX
+ nscert_lock = fsmutex_init("NSCERTMAP", geteuid(),
+ FSMUTEX_VISIBLE|FSMUTEX_NEEDCRIT);
+#else /* XP_WIN32 */
+ char winuser[128];
+ DWORD wulength;
+ strcpy(winuser, "NSCERTMAP_");
+ wulength = 128 - 11;
+ GetUserName(winuser+10, &wulength);
+ nscert_lock = fsmutex_init(winuser, 0,
+ FSMUTEX_VISIBLE|FSMUTEX_NEEDCRIT);
+#endif
+ return (nscert_lock == 0) ? -1 : 0;
+}
+
+NSAPI_PUBLIC int nsadbDecodeCertRec(int reclen, char * recptr,
+ CertObj_t * coptr)
+{
+ ATR_t cp = (ATR_t)recptr; /* current pointer into record */
+ USI_t tag; /* attribute tag */
+ USI_t len; /* attribute value encoding length */
+
+ /* Parse user DB record */
+ while ((cp - (ATR_t)recptr) < reclen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* Process this attribute */
+ switch (tag) {
+
+ case CAT_USERNAME: /* username associated with cert */
+ cp = NTSDECODE(cp, (NTS_t *)&coptr->co_username);
+ break;
+
+ case CAT_CERTID: /* certificate-to-user map id */
+ cp = USIDECODE(cp, &coptr->co_certid);
+ break;
+
+ default: /* unrecognized attribute */
+ /* Just skip it */
+ cp += len;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Description (nsadbDecodeCertKey)
+ *
+ * This function decodes information from a certificate key.
+ * Currently a certificate key includes the DER encoding of the
+ * issuer and subject distinguished names. This is used to
+ * uniquely identify client certificates, even across certificate
+ * renewals. SECItems for the issuer and subject are provided
+ * by the caller. These are updated with the pointers and lengths
+ * of DER encodings, which can be decoded using nsadbDecodeCertName()
+ * into SECName structures. The returned SECItems refer to data
+ * in the provided key buffer.
+ *
+ * Arguments:
+ *
+ * keylen - length of the certificate key encoding
+ * keyptr - buffer containing certificate key encoding
+ * issuer - pointer to SECItem for returning issuer
+ * subject - pointer to SECItem for returning subject
+ *
+ * Returns:
+ *
+ * Zero is returned if no errors are encountered. Otherwise -1.
+ */
+
+NSAPI_PUBLIC int nsadbDecodeCertKey(int keylen, char * keyptr,
+ SECItem * issuer, SECItem * subject)
+{
+ ATR_t cp = (ATR_t)keyptr; /* current pointer into DB record */
+ USI_t len; /* attribute value encoding length */
+ USI_t tag; /* attribute tag */
+
+ /* Parse user DB record */
+ while ((cp - (ATR_t)keyptr) < keylen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* Process this attribute */
+ switch (tag) {
+
+ case KAT_ISSUER: /* issuer DER encoding */
+ issuer->len = len;
+ issuer->data = cp;
+ cp += len;
+ break;
+
+ case KAT_SUBJECT: /* subject name DER encoding */
+ subject->len = len;
+ subject->data = cp;
+ cp += len;
+ break;
+
+ default: /* unrecognized attribute */
+ /* Just skip it */
+ cp += len;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Description (nsadbEncodeCertKey)
+ *
+ * This function encodes information provided by the caller into
+ * a certificate key. The certificate key is returned in a
+ * buffer obtained from MALLOC().
+ *
+ * Arguments:
+ *
+ * issuer - pointer to SECItem for issuer DER
+ * subject - pointer to SECItem for subject DER
+ * keylen - returned length of certificate key
+ * keyptr - returned pointer to buffer containing
+ * certificate key encoding
+ *
+ * Returns:
+ *
+ * Zero is returned if no errors are encountered. Otherwise -1.
+ */
+
+NSAPI_PUBLIC int nsadbEncodeCertKey(SECItem * issuer, SECItem * subject,
+ int * keylen, char **keyptr)
+{
+ ATR_t cp; /* pointer into key buffer */
+ ATR_t kptr; /* pointer to key buffer */
+ int klen; /* length of key */
+ int rv = -1;
+
+ /* Compute length of key encoding */
+ klen = 1 + USILENGTH(issuer->len) + issuer->len +
+ 1 + USILENGTH(subject->len) + subject->len;
+
+ /* Allocate buffer to contain the key */
+ kptr = (ATR_t)MALLOC(klen);
+ if (kptr) {
+ /* Encode issuer and subject as attributes */
+ cp = kptr;
+ *cp++ = KAT_ISSUER;
+ cp = USIENCODE(cp, issuer->len);
+ memcpy(cp, issuer->data, issuer->len);
+ cp += issuer->len;
+ *cp++ = KAT_SUBJECT;
+ cp = USIENCODE(cp, subject->len);
+ memcpy(cp, subject->data, subject->len);
+ rv = 0;
+ }
+
+ /* Return length and buffer pointer */
+ if (keylen) *keylen = klen;
+ *keyptr = (char *)kptr;
+
+ return rv;
+}
+
+/*
+ * Description (nsadbEnumCertsHelp)
+ *
+ * This is a local function that is called by NSDB during certificate
+ * to user database enumeration. It decodes certificate records into
+ * CertObj_t structures, and presents them to the caller of
+ * nsadbEnumerateCerts(), via the specified call-back function.
+ * The call-back function return value may be a negative error code,
+ * which will cause enumeration to stop, and the error code will be
+ * returned from nsadbEnumerateCerts(). If the return value of the
+ * call-back function is not negative, it can contain one or more of
+ * the following flags:
+ *
+ * ADBF_KEEPOBJ - do not free the CertObj_t structure
+ * that was passed to the call-back function
+ * ADBF_STOPENUM - stop the enumeration without an error
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * parg - pointer to CertEnumArgs_t structure
+ * keylen - certificate record key length
+ * keyptr - certificate record key
+ * reclen - length of certificate record
+ * recptr - pointer to certificate record contents
+ *
+ * Returns:
+ *
+ * If the call-back returns a negative result, that value is
+ * returned. If the call-back returns ADBF_STOPENUM, then
+ * -1 is returned, causing the enumeration to stop. Otherwise
+ * the return value is zero.
+ */
+
+typedef struct CertEnumArgs_s CertEnumArgs_t;
+struct CertEnumArgs_s {
+ int rv; /* just a return value */
+ void * client; /* the current key for lookup */
+ void * authdb; /* the authentication data base */
+ CertEnumCallback func; /* client's callback function */
+};
+
+static int nsadbEnumCertsHelp(NSErr_t * errp, void * parg,
+ int keylen, char * keyptr,
+ int reclen, char * recptr)
+{
+ CertEnumArgs_t * ce = (CertEnumArgs_t *)parg;
+ CertObj_t * coptr;
+ int rv = NSAERRNOMEM;
+
+ /* Allocate a CertObj_t structure and initialize it */
+ coptr = (CertObj_t *)MALLOC(sizeof(CertObj_t));
+ if (coptr) {
+
+ coptr->co_issuer.data = 0;
+ coptr->co_subject.data = 0;
+ coptr->co_username = 0;
+ coptr->co_certid = 0;
+
+ /* Decode the certificate key */
+ rv = nsadbDecodeCertKey(keylen, keyptr,
+ &coptr->co_issuer, &coptr->co_subject);
+
+ /* Decode the certificate record */
+ rv = nsadbDecodeCertRec(reclen, recptr, coptr);
+
+ /* Pass the CertObj_t to the callback function */
+ rv = (*ce->func)(errp, ce->authdb, ce->client, coptr);
+ if (rv >= 0) {
+
+ /* Count the number of records seen */
+ ce->rv += 1;
+
+ /* Free the user object unless the call-back says not to */
+ if (!(rv & ADBF_KEEPOBJ)) {
+ nsadbFreeCertObj(coptr);
+ }
+ /* Return either 0 or -1, depending on ADBF_STOPENUM */
+ rv = (rv & ADBF_STOPENUM) ? -1 : 0;
+ }
+ else {
+ /* return the error code */
+ ce->rv = rv;
+ }
+ }
+
+ return rv;
+}
+
+/*
+ * Description (nsadbEnumerateClients)
+ *
+ * (See description for nsadbEnumerateUsers)
+ */
+
+NSAPI_PUBLIC int nsadbEnumerateCerts(NSErr_t * errp, void * authdb,
+ void * argp, CertEnumCallback func)
+{
+ AuthDB_t * adb = (AuthDB_t*)authdb;
+ CertEnumArgs_t helper_data;
+ int rv;
+
+ /* Open the certificate subdatabase for read access */
+ rv = nsadbOpenCerts(errp, authdb, ADBF_CREAD);
+ if (rv >= 0) {
+ helper_data.authdb = authdb;
+ helper_data.func = func;
+ helper_data.client = argp;
+ helper_data.rv = 0;
+
+ rv = ndbEnumerate(errp, adb->adb_certdb, NDBF_ENUMNORM,
+ (void*)&helper_data, nsadbEnumCertsHelp);
+ }
+
+ return (rv < 0) ? rv: helper_data.rv;
+}
+
+NSAPI_PUBLIC void nsadbFreeCertObj(CertObj_t * coptr)
+{
+ if (coptr) {
+ FREE(coptr->co_username);
+ FREE(coptr);
+ }
+}
+
+NSAPI_PUBLIC int nsadbGetCertById(NSErr_t * errp, void * authdb,
+ USI_t certid, CertObj_t **coptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ CertObj_t * cop = 0;
+ char * keyptr;
+ char * recptr;
+ int keylen;
+ int reclen;
+ int rv;
+
+ rv = nsadbOpenCerts(errp, authdb, ADBF_CREAD);
+ if (rv < 0) goto punt;
+
+ /* Get the name corresponding to the id */
+ rv = ndbIdToName(errp, adb->adb_certdb, certid, &keylen, &keyptr);
+ if (rv < 0) goto punt;
+
+ rv = ndbFindName(errp, adb->adb_certdb,
+ keylen, keyptr, &reclen, &recptr);
+ if (rv < 0) goto punt;
+
+ /* Allocate a CertObj_t structure and initialize it */
+ cop = (CertObj_t *)MALLOC(sizeof(CertObj_t));
+ if (cop) {
+
+ cop->co_issuer.data = 0;
+ cop->co_subject.data = 0;
+ cop->co_username = 0;
+ cop->co_certid = 0;
+
+ /* Decode the certificate key */
+ rv = nsadbDecodeCertKey(keylen, keyptr,
+ &cop->co_issuer, &cop->co_subject);
+
+ /* Decode the certificate record */
+ rv = nsadbDecodeCertRec(reclen, recptr, cop);
+
+ }
+
+ punt:
+ if (coptr) *coptr = cop;
+ return rv;
+}
+
+/*
+ * Description (nsadbGetUserByCert)
+ *
+ * This function looks up a specified client certificate in the
+ * authentication database. It returns a pointer to the username
+ * associated with the client certificate, if any. The username
+ * buffer remains valid until the authentication database is
+ * closed.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * cert - pointer to client certificate
+ * username - pointer to returned user name (or null)
+ *
+ * Returns:
+ *
+ * The return value will be zero if the certificate is found. Also,
+ * *username will be set to the string value of the associated username
+ * iff username is not null.
+ */
+
+NSAPI_PUBLIC int nsadbGetUserByCert(NSErr_t * errp, void * authdb,
+ CERTCertificate * cert, char **username)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ ATR_t cp; /* current pointer into DB record */
+ char * user = 0; /* pointer to username */
+ char * keyptr = 0; /* pointer to cert key */
+ char * recptr; /* pointer to cert db record */
+ int keylen; /* length of cert key */
+ int reclen; /* length of cert db record */
+ USI_t tag; /* attribute tag */
+ USI_t len; /* attribute value encoding length */
+ int rv;
+
+ /* Construct the record key from the certificate */
+ rv = nsadbEncodeCertKey(&cert->derIssuer, &cert->derSubject,
+ &keylen, &keyptr);
+
+ if (adb->adb_certdb == NULL) {
+ rv = nsadbOpenCerts(errp, authdb, ADBF_CREAD);
+ if (rv < 0) goto punt;
+ }
+
+ rv = ndbFindName(errp, adb->adb_certdb,
+ keylen, keyptr, &reclen, &recptr);
+ if (rv < 0) goto punt;
+
+ /* Parse cert DB record */
+ cp = (ATR_t)recptr;
+
+ while ((cp - (ATR_t)recptr) < reclen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* We want the CAT_USERNAME attribute */
+ if (tag == CAT_USERNAME) {
+
+ /* Get the username associated with the cert */
+ user = (char *)cp;
+ break;
+ }
+
+ /* Just skip other attributes */
+ cp += len;
+ }
+
+ punt:
+ if (keyptr) {
+ FREE(keyptr);
+ }
+ if (username) *username = user;
+ return rv;
+}
+
+/*
+ * Description (see description for nsadbOpenUsers)
+ */
+
+int nsadbOpenCerts(NSErr_t * errp, void * authdb, int flags)
+{
+ AuthDB_t *adb = (AuthDB_t*)authdb;
+ char *dbname = NULL; /* user database name */
+ int dblen; /* strlen(adb_dbname) */
+ int version; /* database version */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ if (adb == NULL) goto err_inval;
+
+ /* Is the user database already open? */
+ if (adb->adb_certdb != 0) {
+
+ /* Yes, is it open for the desired access? */
+ if (adb->adb_flags & flags) {
+
+ /* Yes, that was easy */
+ return 0;
+ }
+ }
+ else {
+ /* Allocate space for the user database filename */
+ dblen = strlen(adb->adb_dbname);
+
+ dbname = (char *)MALLOC(dblen + strlen(ADBCERTDBNAME) + 2);
+ if (dbname == 0) goto err_nomem;
+
+ /* Construct user database name */
+ strcpy(dbname, adb->adb_dbname);
+
+ /* Put in a '/' (or '\') if it's not there */
+ if (dbname[dblen-1] != FILE_PATHSEP) {
+ dbname[dblen] = FILE_PATHSEP;
+ dbname[dblen+1] = 0;
+ ++dblen;
+ }
+
+ strcpy(&dbname[dblen], ADBCERTDBNAME);
+
+ if (nscert_lock == 0) {
+ rv = nsadbCertInitialize();
+ if (rv < 0) goto err_lock;
+ }
+ adb->adb_certlock = nscert_lock;
+ if (adb->adb_certlock == 0) goto punt;
+
+ fsmutex_lock((FSMUTEX)(adb->adb_certlock));
+
+ adb->adb_certdb = ndbOpen(errp,
+ dbname, 0, NDB_TYPE_CLIENTDB, &version);
+ if (adb->adb_certdb == 0) {
+ fsmutex_unlock((FSMUTEX)(adb->adb_certlock));
+ goto err_open;
+ }
+ }
+
+ /*
+ * We don't really reopen the database to get the desired
+ * access mode, since that is handled at the nsdb level.
+ * But we do update the flags, just for the record.
+ */
+ adb->adb_flags &= ~(ADBF_CREAD|ADBF_CWRITE);
+ if (flags & ADBF_CWRITE) adb->adb_flags |= ADBF_CWRITE;
+ else adb->adb_flags |= ADBF_CREAD;
+ rv = 0;
+
+ punt:
+ if (dbname != NULL) FREE(dbname);
+ return rv;
+
+ err_inval:
+ eid = NSAUERR3400;
+ rv = NSAERRINVAL;
+ goto err_ret;
+
+ err_nomem:
+ eid = NSAUERR3420;
+ rv = NSAERRNOMEM;
+ goto err_ret;
+
+ err_lock:
+ eid = NSAUERR3430;
+ rv = NSAERRLOCK;
+ goto err_ret;
+
+ err_open:
+ eid = NSAUERR3440;
+ rv = NSAERROPEN;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, dbname);
+ goto punt;
+
+}
+
+NSAPI_PUBLIC void nsadbCloseCerts(void * authdb, int flags)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+
+ if (adb->adb_certnm != 0) {
+ /* Close the username-to-certid database */
+ nsadbCloseCertUsers(authdb, flags);
+ }
+
+ if (adb->adb_certdb != 0) {
+
+ ndbClose(adb->adb_certdb, 0);
+ adb->adb_certdb = 0;
+
+ /*
+ * A lock is held for the certificate map DB as long as it is
+ * open, so release the lock now.
+ */
+ fsmutex_unlock((FSMUTEX)(adb->adb_certlock));
+ }
+}
+
+/*
+ * Description (nsadbOpenCertUsers)
+ *
+ * This function opens a database that maps user names to client
+ * certificates. The database appears as "Certs.nm" in the
+ * authentication database directory. This function requires
+ * that the primary certificate database be opened (Certs.db)
+ * first, and will open it if necessary, acquiring a global
+ * lock in the process. The lock will not be released until
+ * nsadbCloseCerts() or nsadbClose() is called.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * flags - same as nsadbOpenCerts()
+ *
+ * Returns:
+ *
+ * The return value is zero if the operation is successful.
+ * Otherwise a negative error code is returned.
+ */
+
+NSAPI_PUBLIC int nsadbOpenCertUsers(NSErr_t * errp, void * authdb, int flags)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ char * dbname = 0;
+ int dblen;
+ int oflags = O_RDONLY; /* assume read-only access */
+ int eid;
+ int rv;
+
+ /* The primary certificate mapping database must be open first */
+ if (adb->adb_certdb != 0) {
+
+ /* It's open, but is it read-only when we need write? */
+ if (((flags & adb->adb_flags) == 0) && (flags & ADBF_CWRITE)) {
+
+ /* Yes, close it */
+ nsadbCloseCerts(authdb, 0);
+ }
+ }
+
+ /* Open it for the desired access if necessary */
+ if (adb->adb_certdb == 0) {
+ /*
+ * Open it for the desired access. Note that this acquires
+ * a global lock which is not released until nsadbClose() is
+ * called for the entire authentication database.
+ */
+ rv = nsadbOpenCerts(errp, authdb, flags);
+ if (rv < 0) {
+ /* Go no further if that failed */
+ return rv;
+ }
+ }
+
+ /* Now look at the username-to-certid database in particular */
+ if (adb->adb_certnm && (adb->adb_flags & flags)) {
+
+ /* The database is already open for the desired access */
+ return 0;
+ }
+
+ dblen = strlen(adb->adb_dbname);
+ dbname = (char *)MALLOC(dblen + strlen(ADBUMAPDBNAME) + 2);
+ strcpy(dbname, adb->adb_dbname);
+ if (dbname[dblen-1] != FILE_PATHSEP) {
+ dbname[dblen] = FILE_PATHSEP;
+ dbname[++dblen] = 0;
+ }
+ strcpy(&dbname[dblen], ADBUMAPDBNAME);
+
+ /* Check for write access and set open flags appropriately if so */
+ if (flags & ADBF_CWRITE) {
+ oflags = O_CREAT|O_RDWR;
+ }
+
+ /* Open the username-to-certid database */
+// adb->adb_certnm = dbopen(dbname, oflags, 0644, DB_HASH, 0);
+ adb->adb_certnm = 0;
+ if (adb->adb_certnm == 0) goto err_open;
+
+ punt:
+ FREE(dbname);
+
+ return rv;
+
+ err_open:
+ eid = NSAUERR3600;
+ rv = NSAERROPEN;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, dbname);
+ goto punt;
+}
+
+/*
+ * Description (nsadbFindCertUser)
+ *
+ * This function checks to see whether a client certificate is
+ * registered for a specified user name. If so, it returns the
+ * certificate mapping id (for use with nsadbGetCertById()).
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * username - pointer to user name string
+ * id - pointer to returned certificate mapping id
+ *
+ * Returns:
+ *
+ * If a certificate is registered for the specified user, the return
+ * value is zero and the certificate mapping id is returned via 'id'.
+ * Otherwise the return value is a negative error code (nsautherr.h)
+ * and an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbFindCertUser(NSErr_t * errp, void * authdb,
+ const char * username, USI_t * id)
+{
+ int eid;
+ int rv;
+ eid = NSAUERR3700;
+ rv = NSAERRNAME;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ return rv;
+}
+
+/*
+ * Description (nsadbAddCertUser)
+ *
+ * This function adds an entry to the username-to-cert id database,
+ * with a given username and certificate mapping id.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * username - pointer to user name string
+ * id - certificate mapping id
+ *
+ * Returns:
+ *
+ * If the entry is added successfully, the return value is zero.
+ * Otherwise the return value is a negative error code (nsautherr.h)
+ * and an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbAddCertUser(NSErr_t * errp, void * authdb,
+ const char * username, USI_t id)
+{
+ /* Need to be ported on NSS 3.2 */
+ int eid;
+ int rv;
+
+ eid = NSAUERR3800;
+ rv = NSAERRPUT;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ return rv;
+}
+
+NSAPI_PUBLIC int nsadbRemoveCertUser(NSErr_t * errp, void * authdb,
+ char * username)
+{
+ /* Need to be ported on NSS 3.2 */
+ int eid;
+ int rv;
+
+ eid = NSAUERR3800;
+ rv = NSAERRPUT;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ return rv;
+}
+
+NSAPI_PUBLIC void nsadbCloseCertUsers(void * authdb, int flags)
+{
+ /* Need to be ported on NSS 3.2 */
+}
+
+/*
+ * Description (nsadbPutUserByCert)
+ *
+ * This function looks up a stores a client certificate mapping
+ * in the authentication database along with the associated username.
+ * It assumes that a record with the specified certificate key does
+ * not already exist, and will replace it if it does.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * certLen - length of the certificate key
+ * cert - certificate key pointer
+ * user - username to be associated with the
+ * certificate
+ *
+ * Returns:
+ *
+ */
+
+NSAPI_PUBLIC int nsadbPutUserByCert(NSErr_t * errp, void * authdb,
+ CERTCertificate * cert,
+ const char * username)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ ATR_t cp; /* pointer into cert record contents */
+ char * keyptr = 0; /* pointer to cert record key */
+ char * recptr = 0; /* pointer to cert record contents */
+ int keylen; /* length of cert record key */
+ int reclen; /* length of cert record contents */
+ USI_t certid;
+ int usrlen;
+ int certidlen;
+ int eid;
+ int rv;
+
+ /* Construct the record key from the certificate */
+ rv = nsadbEncodeCertKey(&cert->derIssuer, &cert->derSubject,
+ &keylen, &keyptr);
+
+ /* Open the username-to-cert id database for write */
+ rv = nsadbOpenCertUsers(errp, authdb, ADBF_CWRITE);
+ if (rv) goto punt;
+
+ /* If the username is already mapped to a cert, it's an error */
+ certid = 0;
+ rv = nsadbFindCertUser(errp, authdb, username, &certid);
+ if (rv == 0) goto err_map;
+
+ /*
+ * Allocate a certificate id and write a record mapping this id
+ * to the specified certificate key.
+ */
+ certid = 0;
+ rv = ndbAllocId(errp, adb->adb_certdb, keylen, keyptr, &certid);
+ if (rv) goto punt;
+
+ /* Record the username as being mapped to the allocated cert id */
+ rv = nsadbAddCertUser(errp, authdb, username, certid);
+ if (rv < 0) goto punt;
+
+ nsadbCloseCertUsers(authdb, 0);
+
+ /*
+ * First we need to figure out how long the generated record will be.
+ * This doesn't have to be exact, but it must not be smaller than the
+ * actual record size.
+ */
+
+ /* CAT_USERNAME attribute: tag, length, NTS */
+ usrlen = NTSLENGTH(username);
+ if (usrlen > 127) goto err_user;
+ reclen = 2 + usrlen;
+
+ /* CAT_CERTID attribute: tag, length, USI */
+ certidlen = USILENGTH(certid);
+ reclen += 2 + certidlen;
+
+ /* Allocate the attribute record buffer */
+ recptr = (char *)MALLOC(reclen);
+ if (recptr) {
+
+ cp = (ATR_t)recptr;
+
+ /* Encode CAT_USERNAME attribute */
+ *cp++ = CAT_USERNAME;
+ *cp++ = usrlen;
+ cp = NTSENCODE(cp, (NTS_t)username);
+
+ /* Encode CAT_CERTID attribute */
+ *cp++ = CAT_CERTID;
+ *cp++ = certidlen;
+ cp = USIENCODE(cp, certid);
+ }
+
+ /* Store the record in the database under the certificate key */
+ rv = ndbStoreName(errp, adb->adb_certdb,
+ 0, keylen, keyptr, reclen, recptr);
+
+ punt:
+ if (keyptr) {
+ FREE(keyptr);
+ }
+ if (recptr) {
+ FREE(recptr);
+ }
+
+ return rv;
+
+ err_user:
+ eid = NSAUERR3500;
+ rv = NSAERRINVAL;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, adb->adb_dbname);
+ goto punt;
+
+ err_map:
+ eid = NSAUERR3520;
+ rv = NSAERRCMAP;
+ nsadbCloseCertUsers(authdb, 0);
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, adb->adb_dbname);
+ goto punt;
+}
+
+NSAPI_PUBLIC int nsadbRemoveCert(NSErr_t * errp, void * authdb,
+ void * username, CertObj_t * coptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ char * keyptr = 0; /* pointer to cert record key */
+ int keylen; /* length of cert record key */
+ int rv;
+ int rv2;
+
+ /* If a username is specified, require it to match */
+ if (username && strcmp((char *)username, coptr->co_username)) {
+ return 0;
+ }
+
+ /* Construct the record key from the certificate */
+ rv = nsadbEncodeCertKey(&coptr->co_issuer, &coptr->co_subject,
+ &keylen, &keyptr);
+
+ if (adb->adb_certdb == NULL) {
+ rv = nsadbOpenCerts(errp, authdb, ADBF_CWRITE);
+ if (rv < 0) goto punt;
+ }
+
+ /* Remove the username-to-cert id entry from Certs.nm */
+ rv = nsadbOpenCertUsers(errp, authdb, ADBF_CWRITE);
+ if (rv < 0) goto punt;
+ rv = nsadbRemoveCertUser(errp, authdb, coptr->co_username);
+ nsadbCloseCertUsers(authdb, 0);
+
+ /* Free the cert id value, if any */
+ rv = 0;
+ if (coptr->co_certid != 0) {
+ rv = ndbFreeId(errp, adb->adb_certdb,
+ keylen, keyptr, coptr->co_certid);
+ }
+
+ /* Delete the cert record */
+ rv2 = ndbDeleteName(errp, adb->adb_certdb, 0, keylen, keyptr);
+
+ punt:
+ if (keyptr) {
+ FREE(keyptr);
+ }
+ return (rv) ? rv : rv2;
+}
+
+NSAPI_PUBLIC int nsadbRemoveUserCert(NSErr_t * errp,
+ void * authdb, char * username)
+{
+ CertObj_t * coptr = 0;
+ USI_t certid = 0;
+ int rv;
+
+ /*
+ * Open for read access at first. We don't want to create the
+ * database if it's not already there. This will do nothing
+ * if the database is already open for write, since that implies
+ * read access as well.
+ */
+ rv = nsadbOpenCertUsers(errp, authdb, ADBF_CREAD);
+ if (rv < 0) goto punt;
+
+ /* Find a certificate mapping id for the given username */
+ rv = nsadbFindCertUser(errp, authdb, username, &certid);
+ if (rv < 0) goto punt;
+
+ /* Look up the mapping from the mapping id */
+ rv = nsadbGetCertById(errp, authdb, certid, &coptr);
+ if (rv < 0) goto punt;
+
+ /* It's there, so remove it. This will re-open for write if needed. */
+ rv = nsadbRemoveCert(errp, authdb, (void *)username, coptr);
+
+ punt:
+
+ if (coptr != 0) {
+ nsadbFreeCertObj(coptr);
+ }
+
+ return rv;
+}
+
+#endif /* defined(CLIENT_AUTH) */
diff --git a/lib/libaccess/nsdb.cpp b/lib/libaccess/nsdb.cpp
new file mode 100644
index 00000000..0479b8f3
--- /dev/null
+++ b/lib/libaccess/nsdb.cpp
@@ -0,0 +1,836 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsdb.c)
+ *
+ * This provides access to a Netscape server database.
+ * A server database is composed of two (libdbm) DB files. One
+ * of these (<dbname>.db) contains records indexed by a string
+ * key. These records contain the primary information in the
+ * database. A second DB file (<dbname>.id) is used to map an
+ * integer id value to a string key, which can then be used to
+ * locate a record in the first file.
+ *
+ * Normally the records in the primary DB file will contain the
+ * id values which are used to key the id-to-name DB. When this
+ * is the case, it is possible to construct the id-to-name DB from
+ * the primary DB file, and an interface is provided to facilitate
+ * this.
+ */
+
+#include <stdio.h>
+#include <base/systems.h>
+#include <netsite.h>
+#include <base/file.h>
+#define __PRIVATE_NSDB
+#include <libaccess/nsdb.h>
+
+#include <errno.h>
+
+#define NDBMODE 0644 /* mode for creating files */
+
+char * NSDB_Program = "NSDB"; /* NSDB facility name */
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ * Description (ndbClose)
+ *
+ * This function closes the specified database. This involves
+ * closing the primary and id-to-name DB files, and freeing the
+ * NSDB_t object.
+ *
+ * Arguments:
+ *
+ * ndb - database handle from ndbOpen()
+ * flags - (currently unused - should be zero)
+ *
+ */
+
+void ndbClose(void * ndb, int flags)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+
+ if (ndbp->ndb_flags & (NDBF_WRNAME|NDBF_RDNAME)) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ }
+
+ if (ndbp->ndb_flags & (NDBF_WRID|NDBF_RDID)) {
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ }
+
+ if (ndbp->ndb_pname) {
+ FREE(ndbp->ndb_pname);
+ }
+
+ if (ndbp->ndb_iname) {
+ FREE(ndbp->ndb_iname);
+ }
+
+ FREE(ndbp);
+}
+
+/*
+ * Description (ndbEnumerate)
+ *
+ * This function is called to enumerate the records of the primary
+ * DB file to a caller-specified function. The function specified
+ * by the caller is called with the name (key), length and address
+ * of each record in the primary DB file. The 'flags' argument can
+ * be used to select normal data records, metadata records, or both.
+ * If the 'flags' value is zero, only normal data records are
+ * enumerated. The function specified by the caller returns -1 to
+ * terminate the enumeration, 0 to continue it, or +1 to restart
+ * the enumeration from the beginning.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * flags - bit flags:
+ * NDBF_ENUMNORM - normal data records
+ * NDBF_ENUMMETA - metadata records
+ * func - pointer to caller's enumeration function
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned, and an error frame is generated if an
+ * error frame list was provided by the caller.
+ */
+
+int ndbEnumerate(NSErr_t * errp, void * ndb, int flags, void * argp,
+#ifdef UnixWare
+ ArgFn_ndbEnum func) /* for ANSI C++ standard, see nsdb.h */
+#else
+ int (*func)(NSErr_t * ferrp, void * parg,
+ int namelen, char * name,
+ int reclen, char * recptr))
+#endif
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ int rv;
+ int dbflag;
+
+ /* Is the user DB open for reading names? */
+ if (!(ndbp->ndb_flags & NDBF_RDNAME)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_RDNAME);
+ if (rv) goto punt;
+ }
+
+ if (flags == 0) flags = NDBF_ENUMNORM;
+
+ for (dbflag = R_FIRST; ; dbflag = (rv > 0) ? R_FIRST : R_NEXT) {
+
+ /* Retrieve the next (first) record from the primary DB */
+ rv = (*ndbp->ndb_pdb->seq)(ndbp->ndb_pdb, &key, &rec, dbflag);
+ if (rv) break;
+
+ /* Is this a metadata record? */
+ if (*(char *)key.data == NDB_MDPREFIX) {
+
+ /* Yes, skip it if metadata was not requested */
+ if (!(flags & NDBF_ENUMMETA)) continue;
+ }
+ else {
+ /* Skip normal data if not requested */
+ if (!(flags & NDBF_ENUMNORM)) continue;
+ }
+
+ /* Pass this record to the caller's function */
+ rv = (*func)(errp, argp,
+ key.size, (char *)key.data, rec.size, (char *)rec.data);
+ if (rv < 0) break;
+ }
+
+ /* Indicate success */
+ rv = 0;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (ndbFindName)
+ *
+ * This function retrieves from the database a record with the
+ * specified key.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * namelen - length of the key, including null
+ * terminator if any
+ * name - pointer to the key of the desired record
+ * reclen - pointer to returned record length
+ * recptr - pointer to returned record pointer
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero, and the length and
+ * address of the returned record are returned through reclen and
+ * recptr. Otherwise the return value is non-zero, and an error
+ * frame is generated if an error frame list was provided by the
+ * caller.
+ *
+ * Notes:
+ *
+ * The record buffer is dynamically allocated and is freed
+ * automatically when the database is closed.
+ */
+
+int ndbFindName(NSErr_t * errp, void * ndb, int namelen, char * name,
+ int * reclen, char **recptr)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Is the user DB open for reading names? */
+ if (!(ndbp->ndb_flags & NDBF_RDNAME)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_RDNAME);
+ if (rv) goto punt;
+ }
+
+ /* Set up record key. Include the terminating null byte. */
+ key.data = (void *)name;
+ key.size = (namelen > 0) ? namelen : (strlen(name) + 1);
+
+ /* Initialize record buffer descriptor */
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Retrieve the record by its key */
+ rv = (*ndbp->ndb_pdb->get)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_pget;
+
+ /* Return record length and address */
+ if (reclen) *reclen = rec.size;
+ if (recptr) *recptr = (char *)rec.data;
+
+ /* Indicate success */
+ rv = 0;
+
+ punt:
+ return rv;
+
+ err_pget:
+ eid = NSDBERR1000;
+ rv = NDBERRGET;
+ nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname, name);
+ goto punt;
+}
+
+/*
+ * Description (ndbIdToName)
+ *
+ * This function looks up a specified id in the id-to-name DB
+ * file, and returns the associated name string. This name
+ * can be used to retrieve a record using ndbFindName().
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * id - id to look up
+ * plen - pointer to returned length of name
+ * (may be null, length includes null terminator
+ * in a string)
+ * pname - pointer to returned name string pointer
+ *
+ * Returns:
+ *
+ * The return value is zero if the operation is successful. An
+ * error is indicated by a negative return value (see nsdberr.h),
+ * and an error frame is generated if an error frame list was
+ * provided by the caller.
+ */
+
+int ndbIdToName(NSErr_t * errp,
+ void * ndb, unsigned int id, int * plen, char **pname)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ char * name = 0;
+ int namelen = 0;
+ uint32 myid = id - 1;
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Is the id-to-name DB open for reading ids? */
+ if (!(ndbp->ndb_flags & NDBF_RDID)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_RDID);
+ if (rv) goto punt;
+ }
+
+ /* Set up record key */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(myid);
+#endif
+ key.data = (void *)&myid;
+ key.size = sizeof(myid);
+
+ /* Initialize record buffer descriptor */
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Retrieve the record by its key */
+ rv = (*ndbp->ndb_idb->get)(ndbp->ndb_idb, &key, &rec, 0);
+ if (rv) goto err_iget;
+
+ /* Get the name pointer (terminating null is part of the name) */
+ namelen = rec.size;
+ name = (char *) rec.data;
+
+ punt:
+ /* Return name length and size if requested */
+ if (plen) *plen = namelen;
+ if (pname) *pname = name;
+
+ return rv;
+
+ err_iget:
+ eid = NSDBERR1100;
+ rv = NDBERRGET;
+ nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2, ndbp->ndb_iname, system_errmsg());
+ goto punt;
+}
+
+/*
+ * Description (ndbInitPrimary)
+ *
+ * This function creates and initializes the primary DB file.
+ * Initialization involves writing any required metadata records.
+ * Currently there is a ?dbtype record, which specifies the nsdb
+ * version number, and a database type and version number that
+ * were passed as arguments to ndbOpen(). There is also a
+ * ?idmap record, which contains an allocation bitmap for id values
+ * used as keys in the associated id-to-name DB file.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned, and an error frame is generated if an
+ * error frame list was provided by the caller.
+ */
+
+int ndbInitPrimary(NSErr_t * errp, void * ndb)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint32 m;
+ int i;
+#endif
+ int eid; /* error id code */
+ int rv; /* result value */
+ uint32 dbtype[4];
+
+ /* Error if the primary DB is marked as existing already */
+ if (!(ndbp->ndb_flags & NDBF_NONAME)) goto err_exists;
+
+ /* First create the primary DB file */
+ ndbp->ndb_pdb = dbopen(ndbp->ndb_pname, O_RDWR | O_CREAT | O_TRUNC,
+ NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_pdb) goto err_open;
+
+ /* Generate data for the ?dbtype record */
+ dbtype[0] = NDB_VERSION;
+ dbtype[1] = ndbp->ndb_dbtype;
+ dbtype[2] = ndbp->ndb_version;
+ dbtype[3] = 0;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ for (i = 0; i < 4; ++i) {
+ m = dbtype[i];
+ M_32_SWAP(m);
+ dbtype[i] = m;
+ }
+#endif
+
+ /* Set up descriptors for the ?dbtype record key and data */
+ key.data = (void *)NDB_DBTYPE;
+ key.size = strlen(NDB_DBTYPE) + 1;
+
+ rec.data = (void *)dbtype;
+ rec.size = sizeof(dbtype);
+
+ /* Write the ?dbtype record out */
+ rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mput1;
+
+ /* Write out an empty ?idmap record */
+ key.data = (void *)NDB_IDMAP;
+ key.size = strlen(NDB_IDMAP) + 1;
+
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Write the ?idmap record */
+ rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mput2;
+
+ /* Close the DB file */
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+
+ /* Clear the flag that says the primary DB file does not exist */
+ ndbp->ndb_flags &= ~(NDBF_NONAME|NDBF_RDNAME|NDBF_WRNAME);
+
+ /* Indicate success */
+ return 0;
+
+ err_exists:
+ /* Primary database already exists */
+ eid = NSDBERR1200;
+ rv = NDBERREXIST;
+ nserrGenerate(errp, rv, eid, NSDB_Program, 1, ndbp->ndb_pname);
+ return rv;
+
+ err_open:
+ /* Error opening primary database for write */
+ eid = NSDBERR1220;
+ rv = NDBERROPEN;
+ goto err_dbio;
+
+ err_mput1:
+ /* Error writing "?dbtype" record */
+ eid = NSDBERR1240;
+ rv = NDBERRMDPUT;
+ goto err_dbio;
+
+ err_mput2:
+ /* Error writing "?idmap" record */
+ eid = NSDBERR1260;
+ rv = NDBERRMDPUT;
+ goto err_dbio;
+
+ err_dbio:
+ nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2, ndbp->ndb_pname, system_errmsg());
+
+ /* Close the primary DB file if it exists */
+ if (ndbp->ndb_pdb) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ ndbp->ndb_flags &= ~(NDBF_RDNAME|NDBF_WRNAME);
+ }
+
+ /* Delete the file */
+ system_unlink(ndbp->ndb_pname);
+ return rv;
+}
+
+/*
+ * Description (ndbOpen)
+ *
+ * This function opens a server database by name. The specified
+ * name may be the name of the primary DB file, or the name
+ * without the ".db" suffix. This function will attempt to open
+ * both the primary and the id-to-name DB files for read access.
+ * If either of the DB files do not exist, they are not created
+ * here, but a handle for the database will still be returned.
+ * The DB files will be created when a subsequent access writes
+ * to the database. The caller also specifies an application
+ * database type, which is checked against a value stored in
+ * in the database metadata, if the primary DB file exists, or
+ * which is stored in the file metadata when the file is created.
+ * A type-specific version number is passed and returned. The
+ * value passed will be stored in the file metadata if it is
+ * subsequently created. If the file exists, the value in the
+ * file metadata is returned, and it is the caller's responsibility
+ * to interpret it.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * dbname - primary DB filename
+ * flags - (currently unused - should be zero)
+ * dbtype - application DB type (NDB_TYPE_xxxxx)
+ * version - (in/out) type-specific version number
+ *
+ * Returns:
+ *
+ * A handle that can be used for subsequent accesses to the database
+ * is returned, or 0, if an error occurs, and an error frame is
+ * generated if an error frame list was provided by the caller.
+ */
+
+void * ndbOpen(NSErr_t * errp,
+ char * dbname, int flags, int dbtype, int * version)
+{
+ NSDB_t * ndbp = 0; /* database object pointer */
+ char * pname = 0; /* primary DB file name */
+ char * iname = 0; /* id-to-name DB file name */
+ int namelen;
+ uint32 dbtrec[4];
+ uint32 m;
+ DBT key;
+ DBT rec;
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Get the database name */
+ namelen = strlen(dbname);
+ if (!strcmp(&dbname[namelen-3], ".db")) {
+ namelen -= 3;
+ }
+
+ /* Get the primary DB file name */
+ pname = (char *)MALLOC(namelen + 4);
+ if (pname == 0) goto err_nomem1;
+ strncpy(pname, dbname, namelen);
+ strcpy(&pname[namelen], ".db");
+
+ /* Get the id-to-name DB file name */
+ iname = (char *)MALLOC(namelen + 4);
+ if (iname == 0) goto err_nomem2;
+ strncpy(iname, dbname, namelen);
+ strcpy(&iname[namelen], ".id");
+
+ /* Allocate the database object */
+ ndbp = (NSDB_t *)MALLOC(sizeof(NSDB_t));
+ if (ndbp == 0) goto err_nomem3;
+
+ /* Initialize the database object */
+ ndbp->ndb_pname = pname;
+ ndbp->ndb_pdb = 0;
+ ndbp->ndb_iname = iname;
+ ndbp->ndb_idb = 0;
+ ndbp->ndb_flags = 0;
+ ndbp->ndb_dbtype = dbtype;
+ ndbp->ndb_version = (version) ? *version : 0;
+
+ /* Open the primary DB file */
+ ndbp->ndb_pdb = dbopen(pname, O_RDONLY, NDBMODE, DB_HASH, 0);
+
+ /* Was it there? */
+ if (ndbp->ndb_pdb) {
+
+ /* Retrieve the ?dbtype record */
+ key.data = (void *)NDB_DBTYPE;
+ key.size = strlen(NDB_DBTYPE) + 1;
+
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Read the ?dbtype record */
+ rv = (*ndbp->ndb_pdb->get)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mdget;
+
+ /* Check it out */
+ if (rec.size < 16) goto err_fmt;
+
+ /* Copy data to an aligned area */
+ memcpy((void *)dbtrec, rec.data, sizeof(dbtrec));
+
+ /* Get the NSDB version number */
+ m = dbtrec[0];
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(m);
+#endif
+ /* Assume forward compatibility with versions up to current + 0.5 */
+ if (m > (NDB_VERSION + 5)) goto err_vers;
+
+ /* XXX Assume infinite backward compatibility */
+
+ /* Get the application database type */
+ m = dbtrec[1];
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(m);
+#endif
+ /* It's got to match */
+ if (m != dbtype) goto err_type;
+
+ /* Get the type-specific version number */
+ m = dbtrec[3];
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(m);
+#endif
+ /* Don't check it. Just return it. */
+ if (version) *version = m;
+
+ /* The value in dbtrec[3] is currently ignored */
+
+ /* Mark the primary DB file open for read access */
+ ndbp->ndb_flags |= NDBF_RDNAME;
+ }
+ else {
+ /* Indicate that the primary DB file does not exist */
+ ndbp->ndb_flags |= NDBF_NONAME;
+ }
+
+ return (void *)ndbp;
+
+ err_nomem1:
+ eid = NSDBERR1400;
+ rv = NDBERRNOMEM;
+ goto err_nomem;
+
+ err_nomem2:
+ eid = NSDBERR1420;
+ rv = NDBERRNOMEM;
+ goto err_nomem;
+
+ err_nomem3:
+ eid = NSDBERR1440;
+ rv = NDBERRNOMEM;
+ err_nomem:
+ nserrGenerate(errp, rv, eid, NSDB_Program, 0);
+ goto punt;
+
+ err_mdget:
+ eid = NSDBERR1460;
+ rv = NDBERRMDGET;
+ nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname,
+ system_errmsg());
+ goto err_ret;
+
+ err_fmt:
+ eid = NSDBERR1480;
+ rv = NDBERRMDFMT;
+ goto err_ret;
+
+ err_vers:
+ {
+ char vnbuf[16];
+
+ eid = NSDBERR1500;
+ rv = NDBERRVERS;
+ sprintf(vnbuf, "%d", (int)m);
+ nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname, vnbuf);
+ }
+ goto punt;
+
+ err_type:
+ eid = NSDBERR1520;
+ rv = NDBERRDBTYPE;
+ goto err_ret;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, NSDB_Program, 1, ndbp->ndb_pname);
+ goto punt;
+
+ punt:
+ /* Error clean-up */
+ if (pname) FREE(pname);
+ if (iname) FREE(iname);
+ if (ndbp) {
+ /* Close the DB files if we got as far as opening them */
+ if (ndbp->ndb_pdb) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ }
+ if (ndbp->ndb_idb) {
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ }
+ FREE(ndbp);
+ }
+ return 0;
+}
+
+/*
+ * Description (ndbReOpen)
+ *
+ * This function is called to ensure that the primary DB file
+ * and/or the id-to-name DB file are open with specified access
+ * rights. For example, a file may be open for read, and it needs
+ * to be open for write. Both the primary and id-to-name DB files
+ * can be manipulated with a single call.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * flags - (currently unused - should be zero)
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned (NDBERRxxxx - see nsdb.h). If an error
+ * list is provided, an error frame will be generated when the
+ * return value is non-zero.
+ */
+
+int ndbReOpen(NSErr_t * errp, void * ndb, int flags)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ char * dbname; /* database name pointer */
+ int eid;
+ int rv;
+
+ /* Want to read or write the primary DB file? */
+ if (flags & (NDBF_RDNAME|NDBF_WRNAME)) {
+
+ /* Need to open for write? */
+ if ((flags & NDBF_WRNAME) && !(ndbp->ndb_flags & NDBF_WRNAME)) {
+
+ /* If it's already open for read, close it first */
+ if (ndbp->ndb_flags & NDBF_RDNAME) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ ndbp->ndb_flags &= ~NDBF_RDNAME;
+ }
+
+ /* Create it if it doesn't exist */
+ if (ndbp->ndb_flags & NDBF_NONAME) {
+ rv = ndbInitPrimary(errp, ndb);
+ if (rv) goto err_init;
+ }
+
+ /* Open primary DB file for write access */
+ dbname = ndbp->ndb_pname;
+ ndbp->ndb_pdb = dbopen(dbname, O_RDWR, NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_pdb) goto err_open1;
+
+ /* Update flags to indicate successful open */
+ ndbp->ndb_flags |= (NDBF_RDNAME|NDBF_WRNAME);
+ }
+
+ /* Need to open for read? */
+ if ((flags & NDBF_RDNAME) && !(ndbp->ndb_flags & NDBF_RDNAME)) {
+
+ /* If it's already open for write, close it first */
+ if (ndbp->ndb_flags & NDBF_WRNAME) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ ndbp->ndb_flags &= ~(NDBF_RDNAME|NDBF_WRNAME);
+ }
+
+ /* Open primary DB file for read access */
+ dbname = ndbp->ndb_pname;
+ ndbp->ndb_pdb = dbopen(dbname, O_RDONLY, NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_pdb) goto err_open2;
+
+ /* Update flags to indicate successful open */
+ ndbp->ndb_flags |= NDBF_RDNAME;
+ }
+ }
+
+ /* Want to read or write the id-to-name DB file? */
+ if (flags & (NDBF_RDID|NDBF_WRID)) {
+
+ /* Need to open for write? */
+ if ((flags & NDBF_WRID) && !(ndbp->ndb_flags & NDBF_WRID)) {
+
+ /*
+ * If it's not open for read yet, try to open it for read
+ * in order to find out if it exists.
+ */
+ if (!(ndbp->ndb_flags & NDBF_RDID)) {
+
+ /* Open id-to-name DB file for read access */
+ dbname = ndbp->ndb_iname;
+ ndbp->ndb_idb = dbopen(dbname, O_RDONLY, NDBMODE, DB_HASH,0);
+
+ /* Does it exist? */
+ if (ndbp->ndb_idb == 0) {
+
+ /* No, create it */
+ dbname = ndbp->ndb_iname;
+ ndbp->ndb_idb = dbopen(dbname,O_RDWR | O_CREAT | O_TRUNC,
+ NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_idb) goto err_open3;
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ }
+ else {
+ /* Mark it open for read */
+ ndbp->ndb_flags |= NDBF_RDID;
+ }
+ }
+
+ /* If it's already open for read, close it first */
+ if (ndbp->ndb_flags & NDBF_RDID) {
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ ndbp->ndb_flags &= ~NDBF_RDID;
+ }
+
+ /* Open id-to-name DB file for write access */
+ dbname = ndbp->ndb_iname;
+ ndbp->ndb_idb = dbopen(dbname, O_RDWR, NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_idb) goto err_open4;
+
+ /* Update flags to indicate successful open */
+ ndbp->ndb_flags |= (NDBF_RDID|NDBF_WRID);
+ }
+
+ /* Need to open for read? */
+ if ((flags & NDBF_RDID) && !(ndbp->ndb_flags & NDBF_RDID)) {
+
+ /* If it's already open for write, close it first */
+ if (ndbp->ndb_flags & NDBF_WRID) {
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ ndbp->ndb_flags &= ~(NDBF_RDID|NDBF_WRID);
+ }
+
+ /* Open id-to-name DB file for read access */
+ dbname = ndbp->ndb_iname;
+ ndbp->ndb_idb = dbopen(dbname, O_RDONLY, NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_idb) goto err_open5;
+
+ /* Update flags to indicate successful open */
+ ndbp->ndb_flags |= NDBF_RDID;
+ }
+ }
+
+ /* Successful completion */
+ return 0;
+
+ /* Begin error handlers */
+
+ err_init: /* failed to create primary DB file */
+ (void)nserrGenerate(errp, NDBERRPINIT, NSDBERR1600, NSDB_Program,
+ 1,
+ ndbp->ndb_pname /* primary DB filename */
+ );
+ rv = NDBERRPINIT;
+ goto punt;
+
+ err_open1:
+ eid = NSDBERR1620;
+ goto err_open;
+
+ err_open2:
+ eid = NSDBERR1640;
+ goto err_open;
+
+ err_open3:
+ eid = NSDBERR1660;
+ goto err_open;
+
+ err_open4:
+ eid = NSDBERR1680;
+ goto err_open;
+
+ err_open5:
+ eid = NSDBERR1700;
+ goto err_open;
+
+ err_open: /* database open error */
+ rv = NDBERROPEN;
+ (void)nserrGenerate(errp, NDBERROPEN, eid, NSDB_Program,
+ 2, dbname, system_errmsg());
+
+ punt:
+ return rv;
+}
+
+NSPR_END_EXTERN_C
+
diff --git a/lib/libaccess/nsdbmgmt.cpp b/lib/libaccess/nsdbmgmt.cpp
new file mode 100644
index 00000000..c1151e08
--- /dev/null
+++ b/lib/libaccess/nsdbmgmt.cpp
@@ -0,0 +1,685 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsdbmgmt.h)
+ *
+ * The file describes the interface for managing information in
+ * a Netscape (server) database. A database is composed of
+ * two (libdbm) DB files. One of these (<dbname>.db) contains
+ * records indexed by a string key. These records contain the
+ * primary information in the database. A second DB file
+ * (<dbname>.id) is used to map an integer id value to a string
+ * key, which can then be used to locate a record in the first file.
+ * The interface for retrieving information from a database is
+ * described in nsdb.h.
+ */
+
+#include <base/systems.h>
+#include <netsite.h>
+#include <base/file.h>
+#define __PRIVATE_NSDB
+#include <libaccess/nsdbmgmt.h>
+#include <base/util.h>
+
+/*
+ * Description (ndbAllocId)
+ *
+ * This function allocates a unique id to be associated with a
+ * name in the primary DB file. An id bitmap is maintained in
+ * the primary DB file as a metadata record, and an entry is
+ * created in the id-to-name DB for the assigned id and the
+ * specified name. An allocated id value is always non-zero.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * namelen - length of key of the desired record,
+ * including null terminator if any
+ * name - pointer to the key of the desired record
+ * id - pointer to returned id value
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero, and the allocated id
+ * is returned through 'id'. Otherwise a non-zero error code is
+ * returned (NDBERRxxxx - see nsdb.h). If an error list is
+ * provided, an error frame will be generated when the return
+ * value is non-zero.
+ */
+
+int ndbAllocId(NSErr_t * errp,
+ void * ndb, int namelen, char * name, unsigned int * id)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ unsigned char * idmap;
+ unsigned char * newmap = 0;
+ int m;
+ int mmsk;
+ uint32 idval;
+ int myid;
+ int i, n;
+ int rv;
+ long eid;
+
+ /*
+ * Ensure that the name does not start with the metadata
+ * prefix character.
+ */
+ if (!name || (name[0] == NDB_MDPREFIX)) goto err_name;
+
+ /*
+ * Read the primary DB file metadata record containing the id
+ * allocation bitmap.
+ */
+
+ /*
+ * We need the primary and the id-to-name DB files open for write
+ * (and implicitly read) access.
+ */
+ if ((ndbp->ndb_flags & (NDBF_WRNAME|NDBF_WRID))
+ != (NDBF_WRNAME|NDBF_WRID)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, (NDBF_WRNAME|NDBF_WRID));
+ if (rv < 0) goto punt;
+ }
+
+ /* Set the key to the id allocation bitmap record name */
+ key.data = (void *)NDB_IDMAP;
+ key.size = strlen(NDB_IDMAP) + 1;
+
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Retrieve the record by its key */
+ rv = (*ndbp->ndb_pdb->get)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mdget;
+
+ /* Search for an available id in the bitmap */
+ n = rec.size;
+ idmap = (unsigned char *)rec.data;
+
+ for (i = 0, m = 0; i < n; ++i) {
+
+ m = idmap[i];
+ if (m != 0) break;
+ }
+
+ /* Did we find a byte with an available bit? */
+ if (m == 0) {
+
+ /* No, need to grow the bitmap */
+ newmap = (unsigned char *)MALLOC(rec.size + 32);
+ if (newmap == 0) goto err_nomem1;
+
+ /* Initialize free space at the beginning of the new map */
+ for (i = 0; i < 32; ++i) {
+ newmap[i] = 0xff;
+ }
+
+ /* Copy the old map after it */
+ n += 32;
+ for ( ; i < n; ++i) {
+ newmap[i] = idmap[i-32];
+ }
+
+ /* Set i and m to allocate the new highest id value */
+ i = 0;
+ m = 0xff;
+ }
+ else {
+
+ /*
+ * It's unfortunate, but it appears to be necessary to copy the
+ * the ?idmap record into a new buffer before updating it, rather
+ * than simply updating it in place. The problem is that the
+ * libdbm put routine deletes the old record and then re-inserts
+ * it. But once it has deleted the old record, it may take the
+ * opportunity to move another record into the space that the
+ * old record occupied, which is the same space that the new
+ * record occupies. So the new record data is overwritten before
+ * new record is inserted. :-(
+ */
+
+ newmap = (unsigned char *)MALLOC(rec.size);
+ if (newmap == 0) goto err_nomem2;
+
+ memcpy((void *)newmap, (void *)idmap, rec.size);
+ }
+
+ /* Calculate the id associated with the low-order bit of byte i */
+ myid = (n - i - 1) << 3;
+
+ /* Find the first free (set) bit in that word */
+ for (mmsk = 1; !(m & mmsk); mmsk <<= 1, myid += 1) ;
+
+ /* Clear the bit */
+ m &= ~mmsk;
+ newmap[i] = m;
+
+ /* Write the bitmap back out */
+
+ rec.data = (void *)newmap;
+ rec.size = n;
+
+ rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
+
+ /* Check for error on preceding put operation */
+ if (rv) goto err_putpdb;
+
+ /* Create the key for the id-to-name record */
+ idval = myid;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(idval);
+#endif
+
+ key.data = (void *)&idval;
+ key.size = sizeof(uint32);
+
+ rec.data = (void *)name;
+ rec.size = (namelen > 0) ? namelen : (strlen(name) + 1);
+
+ /* Write the id-to-name record */
+ rv = (*ndbp->ndb_idb->put)(ndbp->ndb_idb, &key, &rec, 0);
+ if (rv) goto err_putidb;
+
+ /* Return the id value + 1, to avoid returning a zero id */
+ if (id) *id = myid + 1;
+
+ punt:
+
+ /* Free the new map space if any */
+ if (newmap) {
+ FREE(newmap);
+ }
+
+ return rv;
+
+ err_name: /* invalid name parameter */
+ eid = NSDBERR2000;
+ rv = NDBERRNAME;
+ if (name == 0) {
+ name = "(null)";
+ }
+ else if ((namelen > 0) && (namelen != strlen(name) + 1)) {
+ name = "(unprintable)";
+ }
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2,
+ ndbp->ndb_pname, /* primary DB filename */
+ name /* name string */
+ );
+ goto punt;
+
+ err_mdget: /* error on get from primary DB file */
+ eid = NSDBERR2020;
+ rv = NDBERRMDGET;
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2,
+ ndbp->ndb_pname, /* primary DB filename */
+ (char *)key.data /* key name string */
+ );
+ goto punt;
+
+ err_nomem1:
+ eid = NSDBERR2040;
+ goto err_nomem;
+
+ err_nomem2:
+ eid = NSDBERR2060;
+ err_nomem: /* insufficient memory */
+ rv = NDBERRNOMEM;
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program, 0);
+ goto punt;
+
+ err_putpdb: /* error on put to primary DB file */
+ eid = NSDBERR2080;
+ rv = NDBERRMDPUT;
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2,
+ ndbp->ndb_pname, /* primary DB filename */
+ (char *)key.data /* key name string */
+ );
+ goto punt;
+
+ err_putidb: /* error on put to id-to-name DB */
+ {
+ char idstring[16];
+
+ eid = NSDBERR2100;
+ rv = NDBERRIDPUT;
+
+ util_sprintf(idstring, "%d", myid);
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2,
+ ndbp->ndb_iname, /* id-to-name DB file */
+ idstring /* id value for key */
+ );
+ }
+ goto punt;
+}
+
+/*
+ * Description (ndbDeleteName)
+ *
+ * This function deletes a named record from the primary DB file.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * flags - (currently unused - should be zero)
+ * namelen - length of name key, including null
+ * terminator if any
+ * name - pointer to name key
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned (NDBERRxxxx - see nsdberr.h). If an error
+ * list is provided, an error frame will be generated when the
+ * return value is non-zero.
+ */
+
+int ndbDeleteName(NSErr_t * errp,
+ void * ndb, int flags, int namelen, char * name)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ int eid;
+ int rv;
+
+ /* Is the primary DB open for write access? */
+ if (!(ndbp->ndb_flags & NDBF_WRNAME)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_WRNAME);
+ if (rv) goto punt;
+ }
+
+ /* Set up the key descriptor */
+ key.data = (void *)name;
+ key.size = (namelen > 0) ? namelen : (strlen(name) + 1);
+
+ /* Delete the record from the primary DB file */
+ rv = (*ndbp->ndb_pdb->del)(ndbp->ndb_pdb, &key, 0);
+ if (rv) goto err_delpdb;
+
+ /* Successful completion */
+ return 0;
+
+ /* Begin error handlers */
+
+ err_delpdb: /* error deleting record from primary DB */
+ eid = NSDBERR2200;
+ rv = NDBERRNMDEL;
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2,
+ ndbp->ndb_pname, /* primary DB name */
+ (char *)key.data /* primary key */
+ );
+ punt:
+ return rv;
+}
+
+/*
+ * Description (ndbFreeId)
+ *
+ * This function frees an id value associated with a name in the
+ * primary DB file. It is normally called when the named record
+ * is being deleted from the primary DB file. It deletes the
+ * record in the id-to-name DB file that is keyed by the id value,
+ * and updates the id allocation bitmap in the primary DB file.
+ * The caller may specify the name that is associated with the id
+ * value, in which case the id-to-name record will be fetched,
+ * and the name matched, before the record is deleted. Alternatively
+ * the name parameter can be specified as zero, and id-to-name
+ * record will be deleted without a check.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * namelen - length of name (including null terminator)
+ * name - name associated with the id value (optional)
+ * id - id value to be freed
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned, and an error frame is generated if the
+ * caller provided an error frame list.
+ */
+
+int ndbFreeId(NSErr_t * errp,
+ void * ndb, int namelen, char * name, unsigned int id)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ char * recname;
+ DBT key;
+ DBT rec;
+ uint32 idval;
+ int reclen;
+ int mmsk;
+ unsigned char * idmap = 0;
+ int i;
+ int eid;
+ int rv;
+
+ /*
+ * We need the primary and the id-to-name DB files open for write
+ * (and implicitly read) access.
+ */
+ if ((ndbp->ndb_flags & (NDBF_WRNAME|NDBF_WRID))
+ != (NDBF_WRNAME|NDBF_WRID)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, (NDBF_WRNAME|NDBF_WRID));
+ if (rv) goto punt;
+ }
+
+ /* Was the name for this id value provided by the caller? */
+ if (name) {
+
+ /* Get length of name if not provided */
+ if (namelen <= 0) namelen = strlen(name) + 1;
+
+ /* Yes, look up the id and check for a match */
+ rv = ndbIdToName(errp, ndb, id, &reclen, &recname);
+ if (rv < 0) goto punt;
+
+ /* Fail if the supplied name doesn't match */
+ if ((namelen != reclen) ||
+ strncmp(recname, name, reclen)) goto err_badid1;
+ }
+
+ /* Caller views the id space as starting at 1, but we start at 0 */
+ id -= 1;
+
+ /* Create the key for the id-to-name record */
+ idval = id;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(idval);
+#endif
+
+ key.data = (void *)&idval;
+ key.size = sizeof(uint32);
+
+ /* Delete the id-to-name record */
+ rv = (*ndbp->ndb_idb->del)(ndbp->ndb_idb, &key, 0);
+ if (rv) goto err_del;
+
+ /* Set the key to the id allocation bitmap record name */
+ key.data = (void *)NDB_IDMAP;
+ key.size = strlen(NDB_IDMAP) + 1;
+
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Retrieve the record by its key */
+ rv = (*ndbp->ndb_pdb->get)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mdget;
+
+ /* Make sure the id is in the range of the bitmap */
+ i = (rec.size << 3) - id - 1;
+ if (i < 0) goto err_badid2;
+
+ /*
+ * See comment in ndbAllocId() about updating ?idmap. Bottom line
+ * is: we have to copy the record before updating it.
+ */
+
+ idmap = (unsigned char *)MALLOC(rec.size);
+ if (idmap == 0) goto err_nomem;
+
+ memcpy((void *)idmap, rec.data, rec.size);
+
+ /* Calculate the index of the byte with this id's bit */
+ i >>= 3;
+
+ /* Calculate the bitmask for the bitmap byte */
+ mmsk = 1 << (id & 7);
+
+ /* Set the bit in the bitmap */
+ idmap[i] |= mmsk;
+
+ /* Write the bitmap back out */
+
+ rec.data = (void *)idmap;
+
+ rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mdput;
+
+ punt:
+
+ if (idmap) {
+ FREE(idmap);
+ }
+
+ return rv;
+
+ err_badid1:
+ /* Name associated with id doesn't match supplied name */
+ eid = NSDBERR2300;
+ rv = NDBERRBADID;
+ goto err_id;
+
+ err_del:
+ /* Error deleting id-to-name record */
+ eid = NSDBERR2320;
+ rv = NDBERRIDDEL;
+ goto err_dbio;
+
+ err_mdget:
+ /* Error reading id bitmap from primary DB file */
+ eid = NSDBERR2340;
+ rv = NDBERRMDGET;
+ goto err_dbio;
+
+ err_badid2:
+ eid = NSDBERR2360;
+ rv = NDBERRBADID;
+ err_id:
+ {
+ char idbuf[16];
+
+ util_sprintf(idbuf, "%d", id);
+ nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname, idbuf);
+ }
+ goto punt;
+
+ err_nomem:
+ eid = NSDBERR2380;
+ rv = NDBERRNOMEM;
+ nserrGenerate(errp, rv, eid, NSDB_Program, 0);
+ goto punt;
+
+ err_mdput:
+ eid = NSDBERR2400;
+ rv = NDBERRMDPUT;
+ goto err_dbio;
+
+ err_dbio:
+ nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2, ndbp->ndb_pname, system_errmsg());
+ goto punt;
+}
+
+/*
+ * Description (ndbRenameId)
+ *
+ * This function changes the name associated with a specified id
+ * int the id-to-name DB file.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * namelen - length of new name string, including
+ * null terminator if any
+ * newname - pointer to the new name string
+ * id - id value to be renamed
+ *
+ * Returns:
+ *
+ * The return value is zero if the operation is successful. An
+ * error is indicated by a non-zero return value, and an error
+ * frame is generated if the caller provided an error frame list.
+ */
+
+int ndbRenameId(NSErr_t * errp,
+ void * ndb, int namelen, char * newname, unsigned int id)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ uint32 idval = id - 1;
+ int eid;
+ int rv;
+
+ /*
+ * Ensure that the name does not start with the metadata
+ * prefix character.
+ */
+ if (!newname || (newname[0] == NDB_MDPREFIX)) goto err_name;
+
+ /*
+ * We need the id-to-name DB file open for write
+ * (and implicitly read) access.
+ */
+ if (!(ndbp->ndb_flags & NDBF_WRID)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_WRID);
+ if (rv) goto punt;
+ }
+
+ /* Set up record key */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(idval);
+#endif
+ key.data = (void *)&idval;
+ key.size = sizeof(uint32);
+
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Retrieve the record by its key */
+ rv = (*ndbp->ndb_idb->get)(ndbp->ndb_idb, &key, &rec, 0);
+ if (rv) goto err_idget;
+
+ /* Set up to write the new name */
+ rec.data = (void *)newname;
+ rec.size = (namelen > 0) ? namelen : (strlen(newname) + 1);
+
+ /* Write the id-to-name record */
+ rv = (*ndbp->ndb_idb->put)(ndbp->ndb_idb, &key, &rec, 0);
+ if (rv) goto err_idput;
+
+ punt:
+ return rv;
+
+ err_name:
+ eid = NSDBERR2500;
+ rv = NDBERRNAME;
+ if (newname == 0) newname = "(null)";
+ else if ((namelen > 0) && (namelen != (strlen(newname) + 1))) {
+ newname = "(unprintable)";
+ }
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2,
+ ndbp->ndb_pname, /* primary DB filename */
+ newname /* name string */
+ );
+ goto punt;
+
+ err_idget:
+ /* Error getting id record from id-to-name database */
+ eid = NSDBERR2520;
+ rv = NDBERRGET;
+ goto err_dbio;
+
+ err_idput:
+ /* Error putting id record back to id-to-name database */
+ eid = NSDBERR2540;
+ rv = NDBERRIDPUT;
+ err_dbio:
+ nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2, ndbp->ndb_pname, system_errmsg());
+ goto punt;
+}
+
+/*
+ * Description (ndbStoreName)
+ *
+ * This function stores a record, keyed by a specified name, in the
+ * primary DB file. The record will overwrite any existing record
+ * with the same key, unless NDBF_NEWNAME, is included in the 'flags'
+ * argument. If NDBF_NEWNAME is set, and the record already exists,
+ * it is not overwritten, and an error is returned.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * flags - bit flags:
+ * NDBF_NEWNAME - name is new
+ * namelen - length of name key, including null
+ * terminator if any
+ * name - pointer to name key
+ * reclen - length of the record data
+ * recptr - pointer to the record data
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned, and an error frame is generated if the
+ * caller provided an error frame list.
+ */
+
+int ndbStoreName(NSErr_t * errp, void * ndb, int flags,
+ int namelen, char * name, int reclen, char * recptr)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ int eid;
+ int rv;
+
+ /* Is the primary DB open for write access? */
+ if (!(ndbp->ndb_flags & NDBF_WRNAME)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_WRNAME);
+ if (rv) goto punt;
+ }
+
+ /* Set up the key and record descriptors */
+ key.data = (void *)name;
+ key.size = (namelen > 0) ? namelen : (strlen(name) + 1);
+
+ rec.data = (void *)recptr;
+ rec.size = reclen;
+
+ /* Write the record to the primary DB file */
+ rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec,
+ (flags & NDBF_NEWNAME) ? R_NOOVERWRITE : 0);
+ if (rv) goto err_put;
+
+ punt:
+ return rv;
+
+ err_put:
+ eid = NSDBERR2700;
+ rv = NDBERRPUT;
+ nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2, ndbp->ndb_pname, system_errmsg());
+ goto punt;
+}
diff --git a/lib/libaccess/nseframe.cpp b/lib/libaccess/nseframe.cpp
new file mode 100644
index 00000000..c878940b
--- /dev/null
+++ b/lib/libaccess/nseframe.cpp
@@ -0,0 +1,207 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nseframe.c)
+ *
+ * This module is part of the NSACL_RES_ERROR facility. It contains functions
+ * for allocating, freeing, and managing error frame structures. It
+ * does not contain routines for generating error messages through
+ * the use of a message file.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "libaccess/nserror.h"
+
+/*
+ * Description (nserrDispose)
+ *
+ * This function is used to dispose of an entire list of error
+ * frames when the error information is no longer needed. It
+ * does not free the list head, since it is usually not dynamically
+ * allocated.
+ *
+ * Arguments:
+ *
+ * errp - error frame list head pointer
+ */
+
+void nserrDispose(NSErr_t * errp)
+{
+ /* Ignore null list head */
+ if (errp == 0) return;
+
+ while (errp->err_first) {
+
+ nserrFFree(errp, errp->err_first);
+ }
+}
+
+/*
+ * Description (nserrFAlloc)
+ *
+ * This is the default allocator for error frame structures. It
+ * calls an allocator function indicated by err_falloc, if any,
+ * or else uses MALLOC().
+ *
+ * Arguments:
+ *
+ * errp - error frame list head pointer
+ * (may be null)
+ *
+ * Returns:
+ *
+ * The return value is a pointer to a cleared error frame. The
+ * frame will not have been added to the list referenced by errp.
+ * An allocation error is indicated by a null return value.
+ */
+
+NSEFrame_t * nserrFAlloc(NSErr_t * errp)
+{
+ NSEFrame_t * efp; /* return error frame pointer */
+
+ /* Allocate the error frame */
+ efp = (errp && errp->err_falloc)
+ ? (*errp->err_falloc)(errp)
+ : (NSEFrame_t *)MALLOC(sizeof(NSEFrame_t));
+
+ if (efp) {
+ /* Clear the error frame */
+ memset((void *)efp, 0, sizeof(NSEFrame_t));
+ }
+
+ return efp;
+}
+
+/*
+ * Description (nserrFFree)
+ *
+ * This function frees an error frame structure. If an error list
+ * head is specified, it first checks whether the indicated error
+ * frame is on the list, and removes it if so. If the ef_dispose
+ * field is non-null, the indicated function is called. The error
+ * frame is deallocated using either a function indicated by
+ * err_free in the list head, or FREE() otherwise.
+ *
+ * Arguments:
+ *
+ * errp - error frame list head pointer
+ * (may be null)
+ * efp - error frame pointer
+ */
+
+void nserrFFree(NSErr_t * errp, NSEFrame_t * efp)
+{
+ NSEFrame_t **lefp; /* pointer to error frame pointer */
+ NSEFrame_t * pefp; /* previous error frame on list */
+ int i;
+
+ /* Ignore null error frame pointer */
+ if (efp == 0) return;
+
+ /* Got a list head? */
+ if (errp) {
+
+ /* Yes, see if this frame is on the list */
+ pefp = 0;
+ for (lefp = &errp->err_first; *lefp != 0; lefp = &pefp->ef_next) {
+ if (*lefp == efp) {
+
+ /* Yes, remove it */
+ *lefp = efp->ef_next;
+ if (errp->err_last == efp) errp->err_last = pefp;
+ break;
+ }
+ pefp = *lefp;
+ }
+ }
+
+ /* Free strings referenced by the frame */
+ for (i = 0; i < efp->ef_errc; ++i) {
+ if (efp->ef_errv[i]) {
+ FREE(efp->ef_errv[i]);
+ }
+ }
+
+ /* Free the frame */
+ if (errp && errp->err_ffree) {
+ (*errp->err_ffree)(errp, efp);
+ }
+ else {
+ FREE(efp);
+ }
+}
+
+/*
+ * Description (nserrGenerate)
+ *
+ * This function is called to generate an error frame and add it
+ * to a specified error list.
+ *
+ * Arguments:
+ *
+ * errp - error frame list head pointer
+ * (may be null)
+ * retcode - return code (ef_retcode)
+ * errorid - error id (ef_errorid)
+ * program - program string pointer (ef_program)
+ * errc - count of error arguments (ef_errc)
+ * ... - values for ef_errv[]
+ *
+ * Returns:
+ *
+ * The return value is a pointer to the generated error frame, filled
+ * in with the provided information. An allocation error is indicated
+ * by a null return value.
+ */
+
+NSEFrame_t * nserrGenerate(NSErr_t * errp, long retcode, long errorid,
+ char * program, int errc, ...)
+{
+ NSEFrame_t * efp; /* error frame pointer */
+ char * esp; /* error string pointer */
+ int i;
+ va_list ap;
+
+ /* Null frame list head pointer means do nothing */
+ if (errp == 0) {
+ return 0;
+ }
+
+ /* Limit the number of values in ef_errv[] */
+ if (errc > NSERRMAXARG) errc = NSERRMAXARG;
+
+ /* Allocate the error frame */
+ efp = nserrFAlloc(errp);
+
+ /* Did we get it? */
+ if (efp) {
+
+ /* Yes, copy information into it */
+ efp->ef_retcode = retcode;
+ efp->ef_errorid = errorid;
+ efp->ef_program = program;
+ efp->ef_errc = errc;
+
+ /* Get the string arguments and copy them */
+ va_start(ap, errc);
+ for (i = 0; i < errc; ++i) {
+ esp = va_arg(ap, char *);
+ efp->ef_errv[i] = STRDUP(esp);
+ }
+
+ /* Add the frame to the list (if any) */
+ if (errp) {
+ efp->ef_next = errp->err_first;
+ errp->err_first = efp;
+ if (efp->ef_next == 0) errp->err_last = efp;
+ }
+ }
+
+ /* Return the error frame pointer */
+ return efp;
+}
diff --git a/lib/libaccess/nsgmgmt.cpp b/lib/libaccess/nsgmgmt.cpp
new file mode 100644
index 00000000..922b21bc
--- /dev/null
+++ b/lib/libaccess/nsgmgmt.cpp
@@ -0,0 +1,434 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsgmgmt.c)
+ *
+ * This module contains routines for managing information in a
+ * Netscape group database. Information for a particular group
+ * is modified by retrieving the current information in the form
+ * of a group object (GroupObj_t), calling functions in this module,
+ * to modify the group object, and then calling groupStore() to
+ * write the information in the group object back to the database.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "assert.h"
+#include "libaccess/nsdbmgmt.h"
+#define __PRIVATE_NSGROUP
+#include "libaccess/nsgmgmt.h"
+
+/*
+ * Description (groupAddMember)
+ *
+ * This function adds a member to a group object. The member may
+ * be another group or a user, expressed as a group id or user id,
+ * respectively. The 'isgid' argument is non-zero if the new
+ * member is a group, or zero if it is a user.
+ *
+ * Arguments:
+ *
+ * goptr - group object pointer
+ * isgid - non-zero if 'id' is a group id
+ * zero if 'id' is a user id
+ * id - group or user id to be added
+ *
+ * Returns:
+ *
+ * Returns zero if the specified member is already a direct member
+ * of the group. Returns one if the member was added successfully.
+ */
+
+NSAPI_PUBLIC int groupAddMember(GroupObj_t * goptr, int isgid, USI_t id)
+{
+ USIList_t * uilptr;
+ int rv = 0;
+
+ /* Point to the relevant uid or gid list */
+ uilptr = (isgid) ? &goptr->go_groups : &goptr->go_users;
+
+ /* Add the id to the selected list */
+ rv = usiInsert(uilptr, id);
+ if (rv > 0) {
+ goptr->go_flags |= GOF_MODIFIED;
+ }
+
+ return rv;
+}
+
+/*
+ * Description (groupCreate)
+ *
+ * This function creates a group object, using information about
+ * the group provided by the caller. The strings passed for the
+ * group name and description may be on the stack. The group id
+ * is set to zero, but the group object is marked as being new.
+ * A group id will be assigned when groupStore() is called to add
+ * the group to a group database.
+ *
+ * Arguments:
+ *
+ * name - pointer to group name string
+ * desc - pointer to group description string
+ *
+ * Returns:
+ *
+ * A pointer to a dynamically allocated GroupObj_t structure is
+ * returned.
+ */
+
+NSAPI_PUBLIC GroupObj_t * groupCreate(NTS_t name, NTS_t desc)
+{
+ GroupObj_t * goptr; /* group object pointer */
+
+ goptr = (GroupObj_t *)MALLOC(sizeof(GroupObj_t));
+ if (goptr) {
+ goptr->go_name = (NTS_t)STRDUP((char *)name);
+ goptr->go_gid = 0;
+ goptr->go_flags = (GOF_MODIFIED | GOF_NEW);
+ if (desc) {
+ goptr->go_desc = (desc) ? (NTS_t)STRDUP((char *)desc) : 0;
+ }
+ UILINIT(&goptr->go_users);
+ UILINIT(&goptr->go_groups);
+ UILINIT(&goptr->go_pgroups);
+ }
+
+ return goptr;
+}
+
+/*
+ * Description (groupDeleteMember)
+ *
+ * This function removes a specified member from a group object's
+ * list of members. The member to be remove may be a group or a
+ * user, expressed as a group id or user id, respectively. The
+ * 'isgid' argument is non-zero if the member being removed is a
+ * group, or zero if it is a user.
+ *
+ * Arguments:
+ *
+ * goptr - pointer to group object
+ * isgid - non-zero if 'id' is a group id
+ * zero if 'id' is a user id
+ * id - group or user id to be removed
+ *
+ * Returns:
+ *
+ * The return value is zero if the specified member was not present
+ * in the group object, or one if the member was successfully removed.
+ */
+
+NSAPI_PUBLIC int groupDeleteMember(GroupObj_t * goptr, int isgid, USI_t id)
+{
+ USIList_t * uilptr; /* pointer to list of member users or groups */
+ int rv; /* return value */
+
+ /* Get pointer to appropriate list of ids */
+ uilptr = (isgid) ? &goptr->go_groups : &goptr->go_users;
+
+ /* Remove the specified id */
+ rv = usiRemove(uilptr, id);
+ if (rv > 0) {
+ goptr->go_flags |= GOF_MODIFIED;
+ }
+
+ return rv;
+}
+
+/*
+ * Description (groupEncode)
+ *
+ * This function encodes a group object into a group DB record.
+ *
+ * Arguments:
+ *
+ * goptr - pointer to group object
+ * greclen - pointer to returned record length
+ * grecptr - pointer to returned record pointer
+ *
+ * Returns:
+ *
+ * The function return value is zero if successful. The length
+ * and location of the created attribute record are returned
+ * through 'greclen' and 'grecptr'. A non-zero function value
+ * is returned if there's an error.
+ */
+
+NSAPI_PUBLIC int groupEncode(GroupObj_t * goptr, int * greclen, ATR_t * grecptr)
+{
+ int reclen; /* length of DB record */
+ ATR_t rptr; /* DB record pointer */
+ ATR_t rstart = 0; /* pointer to beginning of DB record */
+ ATR_t glptr; /* saved pointer to UAT_GROUPS length */
+ ATR_t gptr; /* saved pointer to after length at glptr */
+ int gidlen; /* gid encoding length */
+ int fllen; /* flags encoding length */
+ USI_t dsclen; /* group description encoding length */
+ USI_t nulen; /* member user count encoding length */
+ USI_t nglen; /* member group count encoding length */
+ int idcnt; /* count of user or group ids */
+ USI_t * ids; /* pointer to array of user or group ids */
+ int i; /* id index */
+ int rv = -1;
+
+ /*
+ * First we need to figure out how long the generated record will be.
+ * This doesn't have to be exact, but it must not be smaller than the
+ * actual record size.
+ */
+
+ /* GAT_GID attribute: tag, length, USI */
+ gidlen = USILENGTH(goptr->go_gid);
+ reclen = (1 + 1 + gidlen);
+
+ /* GAT_FLAGS attribute: tag, length, USI */
+ fllen = USILENGTH(goptr->go_flags & GOF_DBFLAGS);
+ reclen += (1 + 1 + fllen);
+
+ /* GAT_DESCRIPT attribute: tag, length, NTS */
+ dsclen = NTSLENGTH(goptr->go_desc);
+ reclen += (1 + USILENGTH(dsclen) + dsclen);
+
+ /* GAT_USERS attribute: tag, length, USI(count), USI(uid)... */
+ idcnt = UILCOUNT(&goptr->go_users);
+ nulen = USILENGTH(idcnt);
+ reclen += (1 + USIALLOC() + nulen + (5 * idcnt));
+
+ /* GAT_GROUPS attribute: tag, length, USI(count), USI(gid)... */
+ idcnt = UILCOUNT(&goptr->go_groups);
+ nglen = USILENGTH(idcnt);
+ reclen += (1 + USIALLOC() + nglen + (5 * idcnt));
+
+ /* GAT_PGROUPS attribute: tag, length, USI(count), USI(gid)... */
+ idcnt = UILCOUNT(&goptr->go_pgroups);
+ nglen = USILENGTH(idcnt);
+ reclen += (1 + USIALLOC() + nglen + (5 * idcnt));
+
+ /* Allocate the attribute record buffer */
+ rptr = (ATR_t)MALLOC(reclen);
+ if (rptr) {
+
+ /* Save pointer to start of record */
+ rstart = rptr;
+
+ /* Encode GAT_GID attribute */
+ *rptr++ = GAT_GID;
+ *rptr++ = gidlen;
+ rptr = USIENCODE(rptr, goptr->go_gid);
+
+ /* Encode GAT_FLAGS attribute */
+ *rptr++ = GAT_FLAGS;
+ *rptr++ = fllen;
+ rptr = USIENCODE(rptr, (goptr->go_flags & GOF_DBFLAGS));
+
+ /* Encode GAT_DESCRIPT attribute */
+ *rptr++ = GAT_DESCRIPT;
+ rptr = USIENCODE(rptr, dsclen);
+ rptr = NTSENCODE(rptr, goptr->go_desc);
+
+ /* Encode GAT_USERS attribute */
+ *rptr++ = GAT_USERS;
+
+ /*
+ * Save a pointer to the attribute encoding length, and reserve
+ * space for the maximum encoding size of a USI_t value.
+ */
+ glptr = rptr;
+ rptr += USIALLOC();
+ gptr = rptr;
+
+ /* Encode number of user members */
+ idcnt = UILCOUNT(&goptr->go_users);
+ rptr = USIENCODE(rptr, idcnt);
+
+ /* Generate user ids encodings */
+ ids = UILLIST(&goptr->go_users);
+ for (i = 0; i < idcnt; ++i) {
+ rptr = USIENCODE(rptr, ids[i]);
+ }
+
+ /* Now fix up the GAT_USERS attribute encoding length */
+ glptr = USIINSERT(glptr, (USI_t)(rptr - gptr));
+
+ /* Encode GAT_GROUPS attribute */
+ *rptr++ = GAT_GROUPS;
+
+ /*
+ * Save a pointer to the attribute encoding length, and reserve
+ * space for the maximum encoding size of a USI_t value.
+ */
+ glptr = rptr;
+ rptr += USIALLOC();
+ gptr = rptr;
+
+ /* Encode number of groups */
+ idcnt = UILCOUNT(&goptr->go_groups);
+ rptr = USIENCODE(rptr, idcnt);
+
+ /* Generate group ids encodings */
+ ids = UILLIST(&goptr->go_groups);
+ for (i = 0; i < idcnt; ++i) {
+ rptr = USIENCODE(rptr, ids[i]);
+ }
+
+ /* Now fix up the GAT_GROUPS attribute encoding length */
+ glptr = USIINSERT(glptr, (USI_t)(rptr - gptr));
+
+ /* Encode GAT_PGROUPS attribute */
+ *rptr++ = GAT_PGROUPS;
+
+ /*
+ * Save a pointer to the attribute encoding length, and reserve
+ * space for the maximum encoding size of a USI_t value.
+ */
+ glptr = rptr;
+ rptr += USIALLOC();
+ gptr = rptr;
+
+ /* Encode number of groups */
+ idcnt = UILCOUNT(&goptr->go_pgroups);
+ rptr = USIENCODE(rptr, idcnt);
+
+ /* Generate group ids encodings */
+ ids = UILLIST(&goptr->go_pgroups);
+ for (i = 0; i < idcnt; ++i) {
+ rptr = USIENCODE(rptr, ids[i]);
+ }
+
+ /* Now fix up the GAT_PGROUPS attribute encoding length */
+ glptr = USIINSERT(glptr, (USI_t)(rptr - gptr));
+
+ /* Return record length and location if requested */
+ if (greclen) *greclen = rptr - rstart;
+ if (grecptr) *grecptr = rstart;
+
+ /* Indicate success */
+ rv = 0;
+ }
+
+ return rv;
+}
+
+/*
+ * Description (groupRemove)
+ *
+ * This function is called to remove a group from a specified group
+ * database. Both the primary DB file and the id-to-name DB file
+ * are updated.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * groupdb - handle for group DB access
+ * flags - (unused - must be zero)
+ * name - pointer to group name
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code.
+ */
+
+NSAPI_PUBLIC int groupRemove(NSErr_t * errp, void * groupdb, int flags, NTS_t name)
+{
+ GroupObj_t * goptr; /* group object pointer */
+ int rv;
+ int rv2;
+
+ /* First retrieve the group record */
+ goptr = groupFindByName(errp, groupdb, name);
+ if (!goptr) {
+ /* Error - specified group not found */
+ return NSAERRNAME;
+ }
+
+ /* Free the group id value, if any */
+ rv = 0;
+ if (goptr->go_gid != 0) {
+ rv = ndbFreeId(errp, groupdb, 0, (char *)name, goptr->go_gid);
+ }
+
+ rv2 = ndbDeleteName(errp, groupdb, 0, 0, (char *)name);
+
+ return (rv) ? rv : rv2;
+}
+
+/*
+ * Description (groupStore)
+ *
+ * This function is called to store a group object in the database.
+ * If the object was created by groupCreate(), it is assumed to be
+ * a new group, the group account name must not match any existing
+ * group account names in the database, and a gid is assigned before
+ * adding the group to the database. If the object was created by
+ * groupFindByName(), the information in the group object will
+ * replace the existing database entry for the indicated group
+ * name.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * groupdb - handle for group DB access
+ * flags - (unused - must be zero)
+ * goptr - group object pointer
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code. The group object remains intact in either
+ * case.
+ */
+
+NSAPI_PUBLIC int groupStore(NSErr_t * errp, void * groupdb, int flags, GroupObj_t * goptr)
+{
+ ATR_t recptr = 0;
+ USI_t gid;
+ int reclen = 0;
+ int stflags = 0;
+ int eid;
+ int rv;
+
+ /* If this is a new group, allocate a uid value */
+ if (goptr->go_flags & GOF_NEW) {
+
+ rv = ndbAllocId(errp, groupdb, 0, (char *)goptr->go_name, &gid);
+ if (rv) goto punt;
+
+ goptr->go_gid = gid;
+
+ /* Let the database manager know that this is a new entry */
+ stflags = NDBF_NEWNAME;
+ }
+
+ /* Convert the information in the group object to a DB record */
+ rv = groupEncode(goptr, &reclen, &recptr);
+ if (rv) goto err_nomem;
+
+ /*
+ * Store the record in the database under the group name.
+ * If this is a new entry, a group id to group name mapping
+ * also will be added to the id-to-name DB file.
+ */
+ rv = ndbStoreName(errp, groupdb, stflags,
+ 0, (char *)goptr->go_name, reclen, (char *)recptr);
+
+ FREE(recptr);
+
+ if (rv == 0) {
+ goptr->go_flags &= ~(GOF_NEW | GOF_MODIFIED);
+ }
+
+ punt:
+ return rv;
+
+ err_nomem:
+ eid = NSAUERR2000;
+ rv = NSAERRNOMEM;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ goto punt;
+}
diff --git a/lib/libaccess/nsgroup.cpp b/lib/libaccess/nsgroup.cpp
new file mode 100644
index 00000000..c67c85ba
--- /dev/null
+++ b/lib/libaccess/nsgroup.cpp
@@ -0,0 +1,336 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsgroup.c)
+ *
+ * This module contains routines for accessing information in a
+ * Netscape group database. Group information is returned in the
+ * form of a group object (GroupObj_t), defined in nsauth.h.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "assert.h"
+#define __PRIVATE_NSGROUP
+#include "libaccess/nsgroup.h"
+
+/*
+ * Description (groupDecode)
+ *
+ * This function decodes an external group DB record into a
+ * dynamically allocated GroupObj_t structure. The DB record is
+ * encoded as an attribute record as defined in attrec.h.
+ *
+ * Arguments:
+ *
+ * name - pointer to group name string
+ * greclen - length of the group DB record, in octets
+ * grecptr - pointer to group DB record
+ *
+ * Returns:
+ *
+ * A pointer to the allocated GroupObj_t structure is returned.
+ */
+
+NSAPI_PUBLIC GroupObj_t * groupDecode(NTS_t name, int greclen, ATR_t grecptr)
+{
+ ATR_t cp = grecptr; /* current pointer into DB record */
+ USI_t tag; /* attribute tag */
+ USI_t len; /* attribute value encoding length */
+ int i; /* group id index */
+ int idcnt; /* count of user or group ids */
+ USI_t * ids; /* pointer to array of ids */
+ GroupObj_t * goptr; /* group object pointer */
+
+ /* Allocate a group object structure */
+ goptr = (GroupObj_t *)MALLOC(sizeof(GroupObj_t));
+ if (goptr) {
+
+ goptr->go_name = (unsigned char *) STRDUP((char *)name);
+ goptr->go_gid = 0;
+ goptr->go_flags = GOF_MODIFIED;
+ goptr->go_desc = 0;
+ UILINIT(&goptr->go_users);
+ UILINIT(&goptr->go_groups);
+ UILINIT(&goptr->go_pgroups);
+
+ /* Parse group DB record */
+ while ((cp - grecptr) < greclen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* Process this attribute */
+ switch (tag) {
+
+ case GAT_GID: /* group id */
+ cp = USIDECODE(cp, &goptr->go_gid);
+ break;
+
+ case GAT_FLAGS: /* flags */
+ cp = USIDECODE(cp, &goptr->go_flags);
+ break;
+
+ case GAT_DESCRIPT: /* group description */
+ cp = NTSDECODE(cp, &goptr->go_desc);
+ break;
+
+ case GAT_USERS: /* member users of this group */
+
+ /* First get the number of user ids following */
+ cp = USIDECODE(cp, (unsigned *)&idcnt);
+
+ if (idcnt > 0) {
+
+ /* Allocate space for user ids */
+ ids = usiAlloc(&goptr->go_users, idcnt);
+ if (ids) {
+ for (i = 0; i < idcnt; ++i) {
+ cp = USIDECODE(cp, ids + i);
+ }
+ }
+ }
+ break;
+
+ case GAT_GROUPS: /* member groups of this group */
+
+ /* First get the number of group ids following */
+ cp = USIDECODE(cp, (unsigned *)&idcnt);
+
+ if (idcnt > 0) {
+
+ /* Allocate space for group ids */
+ ids = usiAlloc(&goptr->go_groups, idcnt);
+ if (ids) {
+ for (i = 0; i < idcnt; ++i) {
+ cp = USIDECODE(cp, ids + i);
+ }
+ }
+ }
+ break;
+
+ case GAT_PGROUPS: /* parent groups of this group */
+
+ /* First get the number of group ids following */
+ cp = USIDECODE(cp, (USI_t *)&idcnt);
+
+ if (idcnt > 0) {
+
+ /* Allocate space for group ids */
+ ids = usiAlloc(&goptr->go_pgroups, idcnt);
+ if (ids) {
+ for (i = 0; i < idcnt; ++i) {
+ cp = USIDECODE(cp, ids + i);
+ }
+ }
+ }
+ break;
+
+ default: /* unrecognized attribute */
+ /* Just skip it */
+ cp += len;
+ break;
+ }
+ }
+ }
+
+ return goptr;
+}
+
+/*
+ * Description (groupEnumHelp)
+ *
+ * This is a local function that is called by NSDB during group
+ * database enumeration. It decodes group records into group
+ * objects, and presents them to the caller of groupEnumerate().
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * parg - pointer to GroupEnumArgs_t structure
+ * namelen - length of group record key, including null
+ * terminator
+ * name - group record key (group account name)
+ * reclen - length of group record
+ * recptr - pointer to group record contents
+ *
+ * Returns:
+ *
+ * Returns whatever value is returned from the upcall to the caller
+ * of groupEnumerate().
+ */
+
+static int groupEnumHelp(NSErr_t * errp, void * parg,
+ int namelen, char * name, int reclen, char * recptr)
+{
+ GroupEnumArgs_t * ge = (GroupEnumArgs_t *)parg;
+ GroupObj_t * goptr; /* group object pointer */
+ int rv;
+
+ goptr = groupDecode((NTS_t)name, reclen, (ATR_t)recptr);
+
+ rv = (*ge->func)(errp, ge->user, goptr);
+
+ if (!(ge->flags & GOF_ENUMKEEP)) {
+ FREE(goptr);
+ }
+
+ return rv;
+}
+
+/*
+ * Description (groupEnumerate)
+ *
+ * This function enumerates all of the groups in a specified group
+ * database, calling a caller-specified function with a group object
+ * for each group in the database. A 'flags' value of GOF_ENUMKEEP
+ * can be specified to keep the group objects around (not free them)
+ * after the caller's function returns. Otherwise, each group
+ * object is freed after being presented to the caller's function.
+ * The 'argp' argument is an opaque pointer, which is passed to
+ * the caller's function as 'parg' on each call, along with a
+ * group object pointer.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * groupdb - handle for group DB access
+ * flags - bit flags:
+ * GOF_ENUMKEEP - keep group objects
+ * argp - passed to 'func' as 'parg'
+ * func - pointer to caller's enumeration function
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code.
+ */
+
+NSAPI_PUBLIC int groupEnumerate(NSErr_t * errp, void * groupdb, int flags, void * argp,
+ int (*func)(NSErr_t * ferrp,
+ void * parg, GroupObj_t * goptr))
+{
+ int rv;
+ GroupEnumArgs_t args;
+
+ args.groupdb = groupdb;
+ args.flags = flags;
+ args.func = func;
+ args.user = argp;
+
+ rv = ndbEnumerate(errp,
+ groupdb, NDBF_ENUMNORM, (void *)&args, groupEnumHelp);
+
+ return rv;
+}
+
+/*
+ * Description (groupFindByName)
+ *
+ * This function looks up a group record for a specified group name,
+ * converts the group record to the internal group object form, and
+ * returns a pointer to the group object.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * groupdb - handle for group DB access
+ * name - group name to find
+ *
+ * Returns:
+ *
+ * If successful, the return value is a pointer to a group object
+ * for the specified group. Otherwise it is 0.
+ */
+
+NSAPI_PUBLIC GroupObj_t * groupFindByName(NSErr_t * errp, void * groupdb, NTS_t name)
+{
+ GroupObj_t * goptr = 0;
+ ATR_t grecptr;
+ int greclen;
+ int rv;
+
+ /* Look up the group name in the database */
+ rv = ndbFindName(errp, groupdb, 0, (char *)name, &greclen, (char **)&grecptr);
+ if (rv == 0) {
+
+ /* Got the group record. Decode into a group object. */
+ goptr = groupDecode(name, greclen, grecptr);
+ }
+
+ return goptr;
+}
+
+/*
+ * Description (groupFindByGid)
+ *
+ * This function looks up a group record for a specified group id,
+ * converts the group record to the internal group object form, and
+ * returns a pointer to the group object.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * groupdb - handle for group DB access
+ * gid - group id to find
+ *
+ * Returns:
+ *
+ * If successful, the return value is a pointer to a group object
+ * for the specified group. Otherwise it is 0.
+ */
+
+NSAPI_PUBLIC GroupObj_t * groupFindByGid(NSErr_t * errp, void * groupdb, USI_t gid)
+{
+ GroupObj_t * goptr = 0;
+ NTS_t name;
+ ATR_t grecptr;
+ int greclen;
+ int rv;
+
+ /* Get the group account name corresponding to the gid */
+ rv = ndbIdToName(errp, groupdb, gid, 0, (char **)&name);
+ if (rv == 0) {
+
+ rv = ndbFindName(errp, groupdb, 0, (char *)name, &greclen, (char **)&grecptr);
+ if (rv == 0) {
+
+ /* Got the group record. Decode into a group object. */
+ goptr = groupDecode(name, greclen, grecptr);
+ }
+ }
+
+ return goptr;
+}
+
+/*
+ * Description (groupFree)
+ *
+ * This function is called to free a group object. Group objects
+ * are not automatically freed when a group database is closed.
+ *
+ * Arguments:
+ *
+ * goptr - group object pointer
+ *
+ */
+
+NSAPI_PUBLIC void groupFree(GroupObj_t * goptr)
+{
+ if (goptr) {
+
+ if (goptr->go_name) FREE(goptr->go_name);
+ if (goptr->go_desc) FREE(goptr->go_desc);
+ UILFREE(&goptr->go_users);
+ UILFREE(&goptr->go_groups);
+ UILFREE(&goptr->go_pgroups);
+ FREE(goptr);
+ }
+}
diff --git a/lib/libaccess/nslock.cpp b/lib/libaccess/nslock.cpp
new file mode 100644
index 00000000..2cf0b00b
--- /dev/null
+++ b/lib/libaccess/nslock.cpp
@@ -0,0 +1,268 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nslock.c)
+ *
+ * This modules provides an interprocess locking mechanism, based
+ * on a named lock.
+ */
+
+#include "netsite.h"
+#include "base/file.h"
+#define __PRIVATE_NSLOCK
+#include "nslock.h"
+#include <assert.h>
+
+char * NSLock_Program = "NSLOCK";
+
+#ifdef FILE_UNIX
+/*
+ * The process-wide list of locks, NSLock_List, is protected by the
+ * critical section, NSLock_Crit.
+ */
+CRITICAL NSLock_Crit = 0;
+NSLock_t * NSLock_List = 0;
+#endif /* FILE_UNIX */
+
+/*
+ * Description (nsLockOpen)
+ *
+ * This function is used to initialize a handle for a lock. The
+ * caller specifies a unique name for the lock, and a handle is
+ * returned. The returned handle should be used by only one
+ * thread at a time, i.e. if multiple threads in a process are
+ * using the same lock, they should either have their own handles
+ * or protect a single handle with a critical section.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * lockname - pointer to name of lock
+ * plock - pointer to returned handle for lock
+ *
+ * Returns:
+ *
+ * If successful, a handle for the specified lock is returned via
+ * 'plock', and the return value is zero. Otherwise the return
+ * value is a negative error code (see nslock.h), and an error
+ * frame is generated if an error frame list was provided.
+ */
+
+NSAPI_PUBLIC int nsLockOpen(NSErr_t * errp, char * lockname, void **plock)
+{
+ NSLock_t * nl = 0; /* pointer to lock structure */
+ int len; /* length of lockname */
+ int eid;
+ int rv;
+
+#ifdef FILE_UNIX
+ /* Have we created the critical section for NSLock_List yet? */
+ if (NSLock_Crit == 0) {
+
+ /* Narrow the window for simultaneous initialization */
+ NSLock_Crit = (CRITICAL)(-1);
+
+ /* Create it */
+ NSLock_Crit = crit_init();
+ }
+
+ /* Lock the list of locks */
+ crit_enter(NSLock_Crit);
+
+ /* See if a lock with the specified name exists already */
+ for (nl = NSLock_List; nl != 0; nl = nl->nl_next) {
+ if (!strcmp(nl->nl_name, lockname)) break;
+ }
+
+ /* Create a new lock if we didn't find it */
+ if (nl == 0) {
+
+ len = strlen(lockname);
+
+ nl = (NSLock_t *)PERM_MALLOC(sizeof(NSLock_t) + len + 5);
+ if (nl == 0) goto err_nomem;
+
+ nl->nl_name = (char *)(nl + 1);
+ strcpy(nl->nl_name, lockname);
+ strcpy(&nl->nl_name[len], ".lck");
+ nl->nl_cnt = 0;
+
+ nl->nl_fd = open(nl->nl_name, O_RDWR|O_CREAT|O_EXCL, 0644);
+ if (nl->nl_fd < 0) {
+
+ if (errno != EEXIST) {
+ crit_exit(NSLock_Crit);
+ goto err_create;
+ }
+
+ /* O_RDWR or O_WRONLY is required to use lockf on Solaris */
+ nl->nl_fd = open(nl->nl_name, O_RDWR, 0);
+ if (nl->nl_fd < 0) {
+ crit_exit(NSLock_Crit);
+ goto err_open;
+ }
+ }
+
+ /* Remove ".lck" from the lock name */
+ nl->nl_name[len] = 0;
+
+ /* Create a critical section for this lock (gag!) */
+ nl->nl_crit = crit_init();
+
+ /* Add this lock to NSLock_List */
+ nl->nl_next = NSLock_List;
+ NSLock_List = nl;
+ }
+
+ crit_exit(NSLock_Crit);
+
+#else
+/* write me */
+ nl = (void *)4;
+#endif /* FILE_UNIX */
+
+ *plock = (void *)nl;
+ return 0;
+
+ err_nomem:
+ eid = NSLERR1000;
+ rv = NSLERRNOMEM;
+ nserrGenerate(errp, rv, eid, NSLock_Program, 0);
+ goto punt;
+
+ err_create:
+ eid = NSLERR1020;
+ rv = NSLERRCREATE;
+ goto err_file;
+
+ err_open:
+ eid = NSLERR1040;
+ rv = NSLERROPEN;
+ err_file:
+ nserrGenerate(errp, rv, eid, NSLock_Program, 1, nl->nl_name);
+ punt:
+ if (nl) {
+ FREE(nl);
+ }
+ *plock = 0;
+ return rv;
+}
+
+/*
+ * Description (nsLockAcquire)
+ *
+ * This function is used to acquire exclusive ownership of a lock
+ * previously accessed via nsLockOpen(). The calling thread will
+ * be blocked until the lock is acquired. Other threads in the
+ * process should not be blocked.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * lock - handle for lock from nsLockOpen()
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise the return
+ * value is a negative error code (see nslock.h), and an error
+ * frame is generated if an error frame list was provided.
+ */
+
+NSAPI_PUBLIC int nsLockAcquire(NSErr_t * errp, void * lock)
+{
+ NSLock_t * nl = (NSLock_t *)lock;
+ int eid;
+ int rv;
+
+#ifdef FILE_UNIX
+ /* Enter the critical section for the lock */
+ crit_enter(nl->nl_crit);
+
+ /* Acquire the file lock if we haven't already */
+ if (nl->nl_cnt == 0) {
+ rv = system_flock(nl->nl_fd);
+ if (rv) {
+ crit_exit(nl->nl_crit);
+ goto err_lock;
+ }
+ }
+
+ /* Bump the lock count */
+ nl->nl_cnt++;
+
+ crit_exit(nl->nl_crit);
+#else
+ /* write me */
+#endif /* FILE_UNIX */
+
+ /* Indicate success */
+ return 0;
+
+ err_lock:
+ eid = NSLERR1100;
+ rv = NSLERRLOCK;
+ nserrGenerate(errp, rv, eid, NSLock_Program, 1, nl->nl_name);
+
+ return rv;
+}
+
+/*
+ * Description (nsLockRelease)
+ *
+ * This function is used to release exclusive ownership to a lock
+ * that was previously obtained via nsLockAcquire().
+ *
+ * Arguments:
+ *
+ * lock - handle for lock from nsLockOpen()
+ */
+
+NSAPI_PUBLIC void nsLockRelease(void * lock)
+{
+ NSLock_t * nl = (NSLock_t *)lock;
+
+#ifdef FILE_UNIX
+ assert(nl->nl_cnt > 0);
+
+ crit_enter(nl->nl_crit);
+
+ if (--nl->nl_cnt <= 0) {
+ system_ulock(nl->nl_fd);
+ nl->nl_cnt = 0;
+ }
+
+ crit_exit(nl->nl_crit);
+#endif /* FILE_UNIX */
+}
+
+/*
+ * Description (nsLockClose)
+ *
+ * This function is used to close a lock handle that was previously
+ * acquired via nsLockOpen(). The lock should not be owned.
+ *
+ * Arguments:
+ *
+ * lock - handle for lock from nsLockOpen()
+ */
+
+NSAPI_PUBLIC void nsLockClose(void * lock)
+{
+ NSLock_t * nl = (NSLock_t *)lock;
+
+#ifdef FILE_UNIX
+ /* Don't do anything with the lock, since it will get used again */
+#if 0
+ crit_enter(nl->nl_crit);
+ close(nl->nl_fd);
+ crit_exit(nl->nl_crit);
+ FREE(nl);
+#endif
+#else
+ /* write me */
+#endif FILE_UNIX
+}
diff --git a/lib/libaccess/nsumgmt.cpp b/lib/libaccess/nsumgmt.cpp
new file mode 100644
index 00000000..3db677f0
--- /dev/null
+++ b/lib/libaccess/nsumgmt.cpp
@@ -0,0 +1,456 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsumgmt.c)
+ *
+ * This module contains routines for managing information in a
+ * Netscape user database. Information for a particular user
+ * is modified by retrieving the current information in the form
+ * of a user object (UserObj_t), calling functions in this module,
+ * to modify the user object, and then calling userStore() to
+ * write the information in the user object back to the database.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "assert.h"
+#include "libaccess/nsdbmgmt.h"
+#define __PRIVATE_NSUSER
+#include "libaccess/nsumgmt.h"
+
+/*
+ * Description (userAddGroup)
+ *
+ * This function adds a group id to the list of group ids associated
+ * with a user object.
+ *
+ * Arguments:
+ *
+ * uoptr - user object pointer
+ * gid - group id to be added
+ *
+ * Returns:
+ *
+ * Returns zero if the group id is already present in the group id list.
+ * Returns one if the group id was added successfully.
+ * Returns a negative value if an error occurs.
+ */
+
+int userAddGroup(UserObj_t * uoptr, USI_t gid)
+{
+ int rv;
+
+ rv = usiInsert(&uoptr->uo_groups, gid);
+
+ if (rv > 0) {
+
+ uoptr->uo_flags |= UOF_MODIFIED;
+ }
+
+ return rv;
+}
+
+/*
+ * Description (userCreate)
+ *
+ * This function creates a user object, using information about
+ * the user provided by the caller. The strings passed for the
+ * user account name, password, and real user name may be on the
+ * stack. The user id is set to zero, but the user object is
+ * marked as being new. A user id will be assigned when
+ * userStore() is called to add the user to a user database.
+ *
+ * Arguments:
+ *
+ * name - pointer to user account name string
+ * pwd - pointer to (encrypted) password string
+ * rname - real user name (gecos string)
+ *
+ * Returns:
+ *
+ * A pointer to a dynamically allocated UserObj_t structure is
+ * returned.
+ */
+
+NSAPI_PUBLIC UserObj_t * userCreate(NTS_t name, NTS_t pwd, NTS_t rname)
+{
+ UserObj_t * uoptr; /* user object pointer */
+
+ uoptr = (UserObj_t *)MALLOC(sizeof(UserObj_t));
+ if (uoptr) {
+ uoptr->uo_name = (NTS_t)STRDUP((char *)name);
+ uoptr->uo_pwd = (pwd) ? (NTS_t)STRDUP((char *)pwd) : 0;
+ uoptr->uo_uid = 0;
+ uoptr->uo_flags = (UOF_MODIFIED | UOF_NEW);
+ uoptr->uo_rname = (rname) ? (NTS_t)STRDUP((char *)rname) : 0;
+ UILINIT(&uoptr->uo_groups);
+ }
+
+ return uoptr;
+}
+
+/*
+ * Description (userDeleteGroup)
+ *
+ * This function removes a specified group id from a user object's
+ * list of groups.
+ *
+ * Arguments:
+ *
+ * uoptr - pointer to user object
+ * gid - group id to remove
+ *
+ * Returns:
+ *
+ * The return value is zero if the specified group id was not present
+ * in the user object, or one if the group was successfully removed.
+ */
+
+int userDeleteGroup(UserObj_t * uoptr, USI_t gid)
+{
+ int rv; /* return value */
+
+ rv = usiRemove(&uoptr->uo_groups, gid);
+ if (rv > 0) {
+ uoptr->uo_flags |= UOF_MODIFIED;
+ }
+
+ return rv;
+}
+
+/*
+ * Description (userEncode)
+ *
+ * This function encodes a user object into a user DB record.
+ *
+ * Arguments:
+ *
+ * uoptr - pointer to user object
+ * ureclen - pointer to returned record length
+ * urecptr - pointer to returned record pointer
+ *
+ * Returns:
+ *
+ * The function return value is zero if successful. The length
+ * and location of the created attribute record are returned
+ * through 'ureclen' and 'urecptr'. A non-zero function value
+ * is returned if there's an error.
+ */
+
+int userEncode(UserObj_t * uoptr, int * ureclen, ATR_t * urecptr)
+{
+ int reclen; /* length of DB record */
+ ATR_t rptr; /* DB record pointer */
+ ATR_t rstart = 0; /* pointer to beginning of DB record */
+ ATR_t glptr; /* saved pointer to UAT_GROUPS length */
+ ATR_t gptr; /* saved pointer to after length at glptr */
+ int pwdlen; /* password encoding length */
+ int uidlen; /* uid encoding length */
+ int fllen; /* account flags encoding length */
+ USI_t rnlen; /* real name encoding length */
+ USI_t nglen; /* group count encoding length */
+ USI_t gcnt; /* number of group ids */
+ USI_t * gids; /* pointer to array of group ids */
+ int i; /* group id index */
+ int rv = -1;
+
+ /*
+ * First we need to figure out how long the generated record will be.
+ * This doesn't have to be exact, but it must not be smaller than the
+ * actual record size.
+ */
+
+ /* UAT_PASSWORD attribute: tag, length, NTS */
+ pwdlen = NTSLENGTH(uoptr->uo_pwd);
+ reclen = 1 + 1 + pwdlen;
+ if (pwdlen > 127) goto punt;
+
+ /* UAT_UID attribute: tag, length, USI */
+ uidlen = USILENGTH(uoptr->uo_uid);
+ reclen += (1 + 1 + uidlen);
+
+ /* UAT_ACCFLAGS attribute: tag, length, USI */
+ fllen = USILENGTH(uoptr->uo_flags & UOF_DBFLAGS);
+ reclen += (1 + 1 + fllen);
+
+ /* UAT_REALNAME attribute: tag, length, NTS */
+ rnlen = NTSLENGTH(uoptr->uo_rname);
+ reclen += (1 + USILENGTH(rnlen) + rnlen);
+
+ /* UAT_GROUPS attribute: tag, length, USI(count), USI(gid)... */
+ gcnt = UILCOUNT(&uoptr->uo_groups);
+ nglen = USILENGTH(gcnt);
+ reclen += (1 + USIALLOC() + nglen + (5 * gcnt));
+
+ /* Allocate the attribute record buffer */
+ rptr = (ATR_t)MALLOC(reclen);
+ if (rptr) {
+
+ /* Save pointer to start of record */
+ rstart = rptr;
+
+ /* Encode UAT_PASSWORD attribute */
+ *rptr++ = UAT_PASSWORD;
+ *rptr++ = pwdlen;
+ rptr = NTSENCODE(rptr, uoptr->uo_pwd);
+
+ /* Encode UAT_UID attribute */
+ *rptr++ = UAT_UID;
+ *rptr++ = uidlen;
+ rptr = USIENCODE(rptr, uoptr->uo_uid);
+
+ /* Encode UAT_ACCFLAGS attribute */
+ *rptr++ = UAT_ACCFLAGS;
+ *rptr++ = fllen;
+ rptr = USIENCODE(rptr, (uoptr->uo_flags & UOF_DBFLAGS));
+
+ /* Encode UAT_REALNAME attribute */
+ *rptr++ = UAT_REALNAME;
+ rptr = USIENCODE(rptr, rnlen);
+ rptr = NTSENCODE(rptr, uoptr->uo_rname);
+
+ /* Encode UAT_GROUPS attribute */
+ *rptr++ = UAT_GROUPS;
+
+ /*
+ * Save a pointer to the attribute encoding length, and reserve
+ * space for the maximum encoding size of a USI_t value.
+ */
+ glptr = rptr;
+ rptr += USIALLOC();
+ gptr = rptr;
+
+ /* Encode number of groups */
+ rptr = USIENCODE(rptr, gcnt);
+
+ /* Generate group ids encodings */
+ gids = UILLIST(&uoptr->uo_groups);
+ for (i = 0; i < gcnt; ++i) {
+ rptr = USIENCODE(rptr, gids[i]);
+ }
+
+ /* Now fix up the UAT_GROUPS attribute encoding length */
+ glptr = USIINSERT(glptr, (USI_t)(rptr - gptr));
+
+ /* Return record length and location if requested */
+ if (ureclen) *ureclen = rptr - rstart;
+ if (urecptr) *urecptr = rstart;
+
+ /* Indicate success */
+ rv = 0;
+ }
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (userRemove)
+ *
+ * This function is called to remove a user from a specified user
+ * database. Both the primary DB file and the id-to-name DB file
+ * are updated.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * userdb - handle for user DB access
+ * flags - (unused - must be zero)
+ * name - pointer to user account name
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code.
+ */
+
+NSAPI_PUBLIC int userRemove(NSErr_t * errp, void * userdb, int flags, NTS_t name)
+{
+ UserObj_t * uoptr; /* user object pointer */
+ int rv;
+ int rv2;
+
+ /* First retrieve the user record */
+ uoptr = userFindByName(errp, userdb, name);
+ if (!uoptr) {
+ /* Error - specified user not found */
+ return NSAERRNAME;
+ }
+
+ /* Free the user id value, if any */
+ rv = 0;
+ if (uoptr->uo_uid != 0) {
+ rv = ndbFreeId(errp, userdb, 0, (char *)name, uoptr->uo_uid);
+ }
+
+ rv2 = ndbDeleteName(errp, userdb, 0, 0, (char *)name);
+
+ return (rv) ? rv : rv2;
+}
+
+/*
+ * Description (userRename)
+ *
+ * This function is called to change the account name associated
+ * with an existing user. The caller provides a pointer to a
+ * user object for the existing user (with the current user account
+ * name referenced by uo_name), and the new account name for this
+ * user. A check is made to ensure the uniqueness of the new name
+ * in the specified user database. The account name in the user
+ * object is modified. The user database is not modified until
+ * userStore() is called.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * userdb - handle for user DB access
+ * uoptr - user object pointer
+ * newname - pointer to new account name string
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code. The user object remains intact in either
+ * case.
+ */
+
+NSAPI_PUBLIC int userRename(NSErr_t * errp, void * userdb, UserObj_t * uoptr, NTS_t newname)
+{
+ int reclen; /* user record length */
+ ATR_t recptr = 0; /* user record pointer */
+ char * oldname; /* old user account name */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Save the current account name and replace it with the new one */
+ oldname = (char *)uoptr->uo_name;
+ uoptr->uo_name = (unsigned char *) STRDUP((char *)newname);
+
+ if ((oldname != 0) && !(uoptr->uo_flags & UOF_NEW)) {
+
+ /* Convert the information in the user object to a DB record */
+ rv = userEncode(uoptr, &reclen, &recptr);
+ if (rv) goto err_nomem;
+
+ /*
+ * Store the record in the database
+ * under the new user account name.
+ */
+ rv = ndbStoreName(errp, userdb, NDBF_NEWNAME,
+ 0, (char *)uoptr->uo_name, reclen, (char *)recptr);
+ if (rv) goto punt;
+
+ /* Change the mapping of the user id to the new name */
+ rv = ndbRenameId(errp, userdb, 0, (char *)uoptr->uo_name, uoptr->uo_uid);
+ if (rv) goto punt;
+
+ /* Delete the user record with the old account name */
+ rv = ndbDeleteName(errp, userdb, 0, 0, oldname);
+ if (rv) goto punt;
+ }
+ else {
+ /* Set flags in user object for userStore() */
+ uoptr->uo_flags |= UOF_MODIFIED;
+ }
+
+ punt:
+ if (recptr) {
+ FREE(recptr);
+ }
+ if (oldname) {
+ FREE(oldname);
+ }
+ return rv;
+
+ err_nomem:
+ eid = NSAUERR1000;
+ rv = NSAERRNOMEM;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ goto punt;
+}
+
+/*
+ * Description (userStore)
+ *
+ * This function is called to store a user object in the database.
+ * If the object was created by userCreate(), it is assumed to be
+ * a new user account, the user account name must not match any
+ * existing user account names in the database, and a uid is
+ * assigned before adding the user to the database. If the object
+ * was created by userFindByName(), the information in the user
+ * object will replace the existing database entry for the
+ * indicated user account name.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * userdb - handle for user DB access
+ * flags - (unused - must be zero)
+ * uoptr - user object pointer
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code. The user object remains intact in either
+ * case.
+ */
+
+NSAPI_PUBLIC int userStore(NSErr_t * errp, void * userdb, int flags, UserObj_t * uoptr)
+{
+ ATR_t recptr = 0;
+ USI_t uid;
+ int reclen = 0;
+ int stflags = 0;
+ int eid;
+ int rv;
+
+ /* If this is a new user, allocate a uid value */
+ if (uoptr->uo_flags & UOF_NEW) {
+ /*
+ * Yes, allocate a user id and add a user id to user
+ * account name mapping to the id-to-name DB file.
+ */
+ uid = 0;
+ rv = ndbAllocId(errp, userdb, 0, (char *)uoptr->uo_name, &uid);
+ if (rv) goto punt;
+
+ uoptr->uo_uid = uid;
+
+ /* Let the database manager know that this is a new entry */
+ stflags = NDBF_NEWNAME;
+ }
+
+ /* Convert the information in the user object to a DB record */
+ rv = userEncode(uoptr, &reclen, &recptr);
+ if (rv) goto err_nomem;
+
+ /* Store the record in the database under the user account name. */
+ rv = ndbStoreName(errp, userdb, stflags,
+ 0, (char *)uoptr->uo_name, reclen, (char *)recptr);
+ if (rv) goto punt;
+
+ FREE(recptr);
+ recptr = 0;
+
+ uoptr->uo_flags &= ~(UOF_NEW | UOF_MODIFIED);
+ return 0;
+
+ err_nomem:
+ eid = NSAUERR1100;
+ rv = NSAERRNOMEM;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+
+ punt:
+ if (recptr) {
+ FREE(recptr);
+ }
+ if ((uoptr->uo_flags & UOF_NEW) && (uid != 0)) {
+ /* Free the user id value if we failed after allocating it */
+ ndbFreeId(errp, userdb, 0, (char *)uoptr->uo_name, uid);
+ }
+ return rv;
+}
diff --git a/lib/libaccess/nsuser.cpp b/lib/libaccess/nsuser.cpp
new file mode 100644
index 00000000..158235a5
--- /dev/null
+++ b/lib/libaccess/nsuser.cpp
@@ -0,0 +1,309 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsuser.c)
+ *
+ * This module contains routines for accessing information in a
+ * Netscape user database. User information is returned in the
+ * form of a user object (UserObj_t), defined in nsauth.h.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "assert.h"
+#define __PRIVATE_NSUSER
+#include "libaccess/nsuser.h"
+
+/* Authentication facility name for error frame generation */
+char * NSAuth_Program = "NSAUTH";
+
+/*
+ * Description (userDecode)
+ *
+ * This function decodes an external user DB record into a dynamically
+ * allocated UserObj_t structure. The DB record is encoded as an
+ * attribute record as defined in attrec.h.
+ *
+ * Arguments:
+ *
+ * name - pointer to user account name string
+ * ureclen - length of the user DB record, in octets
+ * urecptr - pointer to user DB record
+ *
+ * Returns:
+ *
+ * A pointer to the allocated UserObj_t structure is returned.
+ */
+
+UserObj_t * userDecode(NTS_t name, int ureclen, ATR_t urecptr)
+{
+ ATR_t cp = urecptr; /* current pointer into DB record */
+ USI_t tag; /* attribute tag */
+ USI_t len; /* attribute value encoding length */
+ USI_t gcnt; /* number of group ids */
+ USI_t * gids; /* pointer to array of group ids */
+ int i; /* group id index */
+ UserObj_t * uoptr; /* user object pointer */
+
+ /* Allocate a user object structure */
+ uoptr = (UserObj_t *)MALLOC(sizeof(UserObj_t));
+ if (uoptr) {
+
+ uoptr->uo_name = (unsigned char *) STRDUP((char *)name);
+ uoptr->uo_pwd = 0;
+ uoptr->uo_uid = 0;
+ uoptr->uo_flags = 0;
+ uoptr->uo_rname = 0;
+ UILINIT(&uoptr->uo_groups);
+
+ /* Parse user DB record */
+ while ((cp - urecptr) < ureclen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* Process this attribute */
+ switch (tag) {
+
+ case UAT_PASSWORD: /* encrypted password */
+ cp = NTSDECODE(cp, &uoptr->uo_pwd);
+ break;
+
+ case UAT_UID: /* user id */
+ cp = USIDECODE(cp, &uoptr->uo_uid);
+ break;
+
+ case UAT_ACCFLAGS: /* account flags */
+ cp = USIDECODE(cp, &uoptr->uo_flags);
+ break;
+
+ case UAT_REALNAME: /* real name of user */
+ cp = NTSDECODE(cp, &uoptr->uo_rname);
+ break;
+
+ case UAT_GROUPS: /* groups which include user */
+
+ /* First get the number of group ids following */
+ cp = USIDECODE(cp, &gcnt);
+
+ if (gcnt > 0) {
+
+ /* Allocate space for group ids */
+ gids = usiAlloc(&uoptr->uo_groups, gcnt);
+ if (gids) {
+ for (i = 0; i < gcnt; ++i) {
+ cp = USIDECODE(cp, gids + i);
+ }
+ }
+ }
+ break;
+
+ default: /* unrecognized attribute */
+ /* Just skip it */
+ cp += len;
+ break;
+ }
+ }
+ }
+
+ return uoptr;
+}
+
+/*
+ * Description (userEnumHelp)
+ *
+ * This is a local function that is called by NSDB during user
+ * database enumeration. It decodes user records into user
+ * objects, and presents them to the caller of userEnumerate().
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * parg - pointer to UserEnumArgs_t structure
+ * namelen - user record key length including null
+ * terminator
+ * name - user record key (user account name)
+ * reclen - length of user record
+ * recptr - pointer to user record contents
+ *
+ * Returns:
+ *
+ * Returns whatever value is returned from the upcall to the caller
+ * of userEnumerate().
+ */
+
+static int userEnumHelp(NSErr_t * errp, void * parg,
+ int namelen, char * name, int reclen, char * recptr)
+{
+ UserEnumArgs_t * ue = (UserEnumArgs_t *)parg;
+ UserObj_t * uoptr; /* user object pointer */
+ int rv;
+
+ uoptr = userDecode((NTS_t)name, reclen, (ATR_t)recptr);
+
+ rv = (*ue->func)(errp, ue->user, uoptr);
+
+ if (!(ue->flags & UOF_ENUMKEEP)) {
+ userFree(uoptr);
+ }
+
+ return rv;
+}
+
+/*
+ * Description (userEnumerate)
+ *
+ * This function enumerates all of the users in a specified user
+ * database, calling a caller-specified function with a user object
+ * for each user in the database. A 'flags' value of UOF_ENUMKEEP
+ * can be specified to keep the user objects around (not free them)
+ * after the caller's function returns. Otherwise, each user
+ * object is freed after being presented to the caller's function.
+ * The 'argp' argument is an opaque pointer, which is passed to
+ * the caller's function as 'parg' on each call, along with a
+ * user object pointer.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * userdb - handle for user DB access
+ * flags - bit flags:
+ * UOF_ENUMKEEP - keep user objects
+ * argp - passed to 'func' as 'parg'
+ * func - pointer to caller's enumeration function
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code, and an error frame is generated if an error
+ * frame list was provided by the caller.
+ */
+
+int userEnumerate(NSErr_t * errp, void * userdb, int flags, void * argp,
+ int (*func)(NSErr_t * ferrp, void * parg, UserObj_t * uoptr))
+{
+ int rv;
+ UserEnumArgs_t args;
+
+ args.userdb = userdb;
+ args.flags = flags;
+ args.func = func;
+ args.user = argp;
+
+ rv = ndbEnumerate(errp,
+ userdb, NDBF_ENUMNORM, (void *)&args, userEnumHelp);
+
+ return rv;
+}
+
+/*
+ * Description (userFindByName)
+ *
+ * This function looks up a user record for a specified user account
+ * name, converts the user record to the internal user object form,
+ * and returns a pointer to the user object.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * userdb - handle for user DB access
+ * name - user account name to find
+ *
+ * Returns:
+ *
+ * If successful, the return value is a pointer to a user object
+ * for the specified user. Otherwise it is 0, and an error frame
+ * is generated if an error frame list was provided by the caller.
+ */
+
+UserObj_t * userFindByName(NSErr_t * errp, void * userdb, NTS_t name)
+{
+ UserObj_t * uoptr = 0;
+ ATR_t urecptr;
+ int ureclen;
+ int rv;
+
+ /* Look up the user name in the database */
+ rv = ndbFindName(errp, userdb, 0, (char *) name, &ureclen, (char **)&urecptr);
+ if (rv == 0) {
+
+ /* Got the user record. Decode into a user object. */
+ uoptr = userDecode(name, ureclen, urecptr);
+ }
+
+ return uoptr;
+}
+
+/*
+ * Description (userFindByUid)
+ *
+ * This function looks up a user record for a specified user id,
+ * converts the user record to the internal user object form, and
+ * returns a pointer to the user object.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * userdb - handle for user DB access
+ * uid - user id to find
+ *
+ * Returns:
+ *
+ * If successful, the return value is a pointer to a user object
+ * for the specified user. Otherwise it is 0, and an error frame
+ * is generated if an error frame list was provided by the caller.
+ */
+
+UserObj_t * userFindByUid(NSErr_t * errp, void * userdb, USI_t uid)
+{
+ UserObj_t * uoptr = 0;
+ NTS_t name;
+ ATR_t urecptr;
+ int ureclen;
+ int rv;
+
+ /* Get the user account name corresponding to the uid */
+ rv = ndbIdToName(errp, userdb, uid, 0, (char **)&name);
+ if (rv == 0) {
+
+ rv = ndbFindName(errp, userdb, 0, (char *)name, &ureclen, (char **)&urecptr);
+ if (rv == 0) {
+
+ /* Got the user record. Decode into a user object. */
+ uoptr = userDecode(name, ureclen, urecptr);
+ }
+ }
+
+ return uoptr;
+}
+
+/*
+ * Description (userFree)
+ *
+ * This function is called to free a user object. User objects
+ * are not automatically freed when a user database is closed.
+ *
+ * Arguments:
+ *
+ * uoptr - user object pointer
+ *
+ */
+
+NSAPI_PUBLIC void userFree(UserObj_t * uoptr)
+{
+ if (uoptr) {
+
+ if (uoptr->uo_name) FREE(uoptr->uo_name);
+ if (uoptr->uo_pwd) FREE(uoptr->uo_pwd);
+ if (uoptr->uo_rname) FREE(uoptr->uo_rname);
+ UILFREE(&uoptr->uo_groups);
+ FREE(uoptr);
+ }
+}
diff --git a/lib/libaccess/oneeval.cpp b/lib/libaccess/oneeval.cpp
new file mode 100644
index 00000000..be837599
--- /dev/null
+++ b/lib/libaccess/oneeval.cpp
@@ -0,0 +1,1054 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (acleval.c)
+ *
+ * This module provides functions for evaluating Access Control List
+ * (ACL) structures in memory.
+ *
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <assert.h>
+
+#include <netsite.h>
+#include <base/systems.h>
+#include <base/crit.h>
+#include <base/session.h>
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include <libaccess/symbols.h>
+#include <libaccess/aclerror.h>
+#include <libaccess/aclglobal.h>
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+#include "access_plhash.h"
+#include "aclutil.h"
+#include "aclcache.h"
+#include "oneeval.h"
+#include "permhash.h"
+
+static int acl_default_result = ACL_RES_DENY;
+
+static ACLDispatchVector_t __nsacl_vector = {
+
+ /* Error frame stack support */
+
+ nserrDispose,
+ nserrFAlloc,
+ nserrFFree,
+ nserrGenerate,
+
+ /* Property list support */
+
+ PListAssignValue,
+ PListCreate,
+ PListDefProp,
+ PListDeleteProp,
+ PListFindValue,
+ PListInitProp,
+ PListNew,
+ PListDestroy,
+ PListGetValue,
+ PListNameProp,
+ PListSetType,
+ PListSetValue,
+ PListEnumerate,
+ PListDuplicate,
+ PListGetPool,
+
+ /* ACL attribute handling */
+
+ ACL_LasRegister,
+
+ /* method/dbtype registration routines */
+
+ ACL_MethodRegister,
+ ACL_MethodIsEqual,
+ ACL_MethodNameIsEqual,
+ ACL_MethodFind,
+ ACL_MethodGetDefault,
+ ACL_MethodSetDefault,
+ ACL_AuthInfoGetMethod,
+
+ ACL_DbTypeRegister,
+ ACL_DbTypeIsEqual,
+ ACL_DbTypeNameIsEqual,
+ ACL_DbTypeFind,
+ ACL_DbTypeGetDefault,
+ ACL_AuthInfoGetDbType,
+ ACL_DbTypeIsRegistered,
+ ACL_DbTypeParseFn,
+
+ ACL_AttrGetterRegister,
+
+ ACL_ModuleRegister,
+ ACL_GetAttribute,
+ ACL_DatabaseRegister,
+ ACL_DatabaseFind,
+ ACL_DatabaseSetDefault,
+ ACL_LDAPDatabaseHandle,
+ ACL_AuthInfoGetDbname,
+ ACL_CacheFlushRegister,
+ ACL_CacheFlush,
+
+ /* ACL language and file interfaces */
+
+ ACL_ParseFile,
+ ACL_ParseString,
+ ACL_WriteString,
+ ACL_WriteFile,
+ ACL_FileRenameAcl,
+ ACL_FileDeleteAcl,
+ ACL_FileGetAcl,
+ ACL_FileSetAcl,
+
+ /* ACL Expression construction interfaces */
+
+ ACL_ExprNew,
+ ACL_ExprDestroy,
+ ACL_ExprSetPFlags,
+ ACL_ExprClearPFlags,
+ ACL_ExprTerm,
+ ACL_ExprNot,
+ ACL_ExprAnd,
+ ACL_ExprOr,
+ ACL_ExprAddAuthInfo,
+ ACL_ExprAddArg,
+ ACL_ExprSetDenyWith,
+ ACL_ExprGetDenyWith,
+ ACL_ExprAppend,
+
+ /* ACL manipulation */
+
+ ACL_AclNew,
+ ACL_AclDestroy,
+
+ /* ACL list manipulation */
+
+ ACL_ListNew,
+ ACL_ListConcat,
+ ACL_ListAppend,
+ ACL_ListDestroy,
+ ACL_ListFind,
+ ACL_ListAclDelete,
+ ACL_ListGetNameList,
+ ACL_NameListDestroy,
+
+ /* ACL evaluation */
+
+ ACL_EvalTestRights,
+ ACL_EvalNew,
+ ACL_EvalDestroy,
+ ACL_EvalSetACL,
+ ACL_EvalGetSubject,
+ ACL_EvalSetSubject,
+ ACL_EvalGetResource,
+ ACL_EvalSetResource,
+
+ /* Access to critical section for ACL cache */
+
+ ACL_CritEnter,
+ ACL_CritExit,
+
+ /* Miscellaneous functions */
+
+ ACL_AclGetTag,
+ ACL_ListGetFirst,
+ ACL_ListGetNext,
+
+ /* Functions added after ES 3.0 release */
+ ACL_DatabaseGetDefault,
+ ACL_SetDefaultResult,
+ ACL_GetDefaultResult
+};
+
+NSAPI_PUBLIC ACLDispatchVector_t *__nsacl_table = &__nsacl_vector;
+
+int ACLEvalAce(
+ NSErr_t *errp,
+ ACLEvalHandle_t *acleval,
+ ACLExprHandle_t *ace,
+ ACLCachable_t *cachable,
+ PList_t autharray[],
+ PList_t global_auth
+ )
+{
+ ACLCachable_t local_cachable;
+ int result;
+ ACLExprEntry_t *expr;
+ int expr_index = 0;
+
+ expr = &ace->expr_arry[0];
+ *cachable = ACL_INDEF_CACHABLE;
+
+ while (TRUE)
+ {
+ local_cachable = ACL_NOT_CACHABLE;
+
+ /* Call the LAS driver */
+ if (!expr->las_eval_func) {
+ ACL_CritEnter();
+ if (!expr->las_eval_func) { /* Must check again after locking */
+ ACL_LasFindEval(errp, expr->attr_name, &expr->las_eval_func);
+ if (!expr->las_eval_func) { /* Couldn't find it */
+ ACL_CritExit();
+ return LAS_EVAL_INVALID;
+ }
+ }
+ ACL_CritExit();
+ }
+ result = (*expr->las_eval_func)(
+ errp,
+ expr->attr_name,
+ expr->comparator,
+ expr->attr_pattern,
+ &local_cachable,
+ &expr->las_cookie,
+ acleval->subject,
+ acleval->resource,
+ autharray ? autharray[expr_index] : NULL,
+ global_auth);
+
+ /* Evaluate the cachable value */
+ if (local_cachable < *cachable) {
+
+ /* Take the minimum value */
+ *cachable = local_cachable;
+ }
+
+ /* Evaluate the return code */
+ switch (result) {
+ case LAS_EVAL_TRUE:
+ if (expr->true_idx < 0)
+ return (expr->true_idx);
+ else {
+ expr_index = expr->true_idx;
+ expr = &ace->expr_arry[expr->true_idx];
+ }
+ break;
+
+ case LAS_EVAL_FALSE:
+ if (expr->false_idx < 0)
+ return (expr->false_idx);
+ else {
+ expr_index = expr->false_idx;
+ expr = &ace->expr_arry[expr->false_idx];
+ }
+ break;
+
+ default:
+ return (result);
+ }
+
+ }
+}
+
+
+int
+ACL_EvalDestroyContext(ACLListCache_t *cache)
+{
+ ACLAceEntry_t *cur_ace, *next_ace;
+ ACLAceNumEntry_t *cur_num_p, *next_num_p;
+ ACLExprHandle_t *acep;
+
+ if (!cache)
+ return 0;
+
+ PR_HashTableDestroy(cache->Table);
+ cache->Table = NULL;
+
+ cur_ace = cache->acelist;
+ cache->acelist = NULL;
+ while (cur_ace) {
+ if (cur_ace->autharray)
+ PERM_FREE(cur_ace->autharray);
+ if ((cur_ace->global_auth) &&
+ (cur_ace->acep->expr_type == ACL_EXPR_TYPE_AUTH))
+ PListDestroy(cur_ace->global_auth);
+ next_ace = cur_ace->next;
+ acep = cur_ace->acep; /* The ACE structure itself */
+ PERM_FREE(cur_ace);
+ cur_ace = next_ace;
+ }
+
+ cur_num_p = cache->chain_head;
+ cache->chain_head = NULL;
+ while (cur_num_p) {
+ next_num_p = cur_num_p->chain;
+ PERM_FREE(cur_num_p);
+ cur_num_p = next_num_p;
+ }
+
+ PERM_FREE(cache);
+
+ return 0;
+}
+
+
+/* ACLEvalBuildContext
+ * Builds three structures:
+ * Table - A hash table of all access rights referenced by any ACE in any
+ * of the ACLs in this list. Each hash entry then has a list of
+ * the relevant ACEs, in the form of indexes to the ACE linked
+ * list.
+ * ACE List - A linked list of all the ACEs in the proper evaluation order.
+ *
+ * For concurrency control, the caller must call ACL_CritEnter()
+ */
+int
+ACLEvalBuildContext(
+ NSErr_t *errp,
+ ACLEvalHandle_t *acleval)
+{
+ ACLHandle_t *acl;
+ ACLExprHandle_t *ace;
+ int ace_cnt = -1;
+ ACLAceEntry_t *acelast, *new_ace;
+ ACLAceNumEntry_t *entry, *temp_entry;
+ char **argp;
+ ACLListCache_t *cache;
+ ACLWrapper_t *wrapper;
+ PList_t curauthplist=NULL, absauthplist=NULL;
+ int i, rv;
+ ACLExprEntry_t *expr;
+ PList_t authplist;
+
+ /* Allocate the cache context and link it into the ACLListHandle */
+ cache = (ACLListCache_t *)PERM_CALLOC(sizeof(ACLListCache_t));
+ if (cache == NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4010, ACL_Program, 0);
+ goto error;
+ }
+
+ /* Allocate the access rights hash table */
+ cache->Table = PR_NewHashTable(0,
+ PR_HashString,
+ PR_CompareStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+
+ if (cache->Table == NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4000, ACL_Program, 1,
+ XP_GetAdminStr(DBT_EvalBuildContextUnableToCreateHash));
+ goto error;
+ }
+
+ wrapper = acleval->acllist->acl_list_head;
+
+ /* Loop through all the ACLs in the list */
+ while (wrapper)
+ {
+ acl = wrapper->acl;
+ ace = acl->expr_list_head;
+
+ while (ace) /* Loop through all the ACEs in this ACL */
+ {
+
+ /* allocate a new ace list entry and link it in to the ordered
+ * list.
+ */
+ new_ace = (ACLAceEntry_t *)PERM_CALLOC(sizeof(ACLAceEntry_t));
+ if (new_ace == (ACLAceEntry_t *)NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4020, ACL_Program, 1,
+ XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAceEntry));
+ goto error;
+ }
+ new_ace->acep = ace;
+ ace_cnt++;
+
+ if (cache->acelist == NULL)
+ cache->acelist = acelast = new_ace;
+ else {
+ acelast->next = new_ace;
+ acelast = new_ace;
+ new_ace->acep = ace;
+ }
+ new_ace->next = NULL;
+
+ argp = ace->expr_argv;
+
+ switch (ace->expr_type)
+ {
+ case ACL_EXPR_TYPE_ALLOW:
+ case ACL_EXPR_TYPE_DENY:
+
+ /* Add this ACE to the appropriate entries in the access rights
+ * hash table
+ */
+ while (*argp)
+ {
+ entry =
+ (ACLAceNumEntry_t *)PERM_CALLOC(sizeof(ACLAceNumEntry_t));
+ if (entry == (ACLAceNumEntry_t *)NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4030, ACL_Program, 1,
+ XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAceEntry));
+ goto error;
+ }
+ if (cache->chain_head == NULL)
+ cache->chain_head = cache->chain_tail = entry;
+ else {
+ cache->chain_tail->chain = entry;
+ cache->chain_tail = entry;
+ }
+ entry->acenum = ace_cnt;
+
+ /*
+ * OK to call PL_HasTableLookup() even though it mods
+ * the Table as this routine is called in critical section.
+ */
+ temp_entry = (ACLAceNumEntry_t *)PL_HashTableLookup(cache->Table, *argp);
+ /* the first ACE for this right? */
+ if (temp_entry) {
+ /* Link it in at the end */
+ while (temp_entry->next) {
+ temp_entry = temp_entry->next;
+ }
+ temp_entry->next = entry;
+ } else /* just link it in */
+ PR_HashTableAdd(cache->Table, *argp, entry);
+
+ argp++;
+
+ }
+
+ /* See if any of the clauses require authentication. */
+ if (curauthplist) {
+ for (i = 0; i < ace->expr_term_index; i++) {
+ expr = &ace->expr_arry[i];
+ rv = PListFindValue(curauthplist, expr->attr_name,
+ NULL, &authplist);
+ if (rv > 0) {
+ /* First one for this ACE? */
+ if (!new_ace->autharray) {
+ new_ace->autharray = (PList_t *)PERM_CALLOC(sizeof(PList_t *) * ace->expr_term_index);
+ if (!new_ace->autharray) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4040, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPointerArray));
+ goto error;
+ }
+ }
+ new_ace->autharray[i] = authplist;
+ }
+ }
+ }
+ break;
+
+ case ACL_EXPR_TYPE_AUTH:
+
+ /* Allocate the running auth tables if none yet */
+ if (!curauthplist) {
+ curauthplist = PListNew(NULL);
+ if (!curauthplist) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4050, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPlist));
+ goto error;
+ }
+ absauthplist = PListNew(NULL);
+ if (!absauthplist) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4050, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPlist));
+ goto error;
+ }
+ } else { /* duplicate the existing auth table */
+ curauthplist = PListDuplicate(curauthplist, NULL, 0);
+ if (!curauthplist) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4050, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPlist));
+ goto error;
+ }
+ }
+
+ /* For each listed attribute */
+ while (*argp)
+ {
+ /* skip any attributes that were absoluted */
+ if (PListFindValue(absauthplist, *argp, NULL, NULL) < 0)
+ {
+ /* Save pointer to the property list */
+ PListInitProp(curauthplist, NULL, *argp, ace->expr_auth,
+ ace->expr_auth);
+ if (IS_ABSOLUTE(ace->expr_flags))
+ PListInitProp(absauthplist, NULL, *argp, NULL,
+ NULL);
+ }
+
+ argp++;
+ }
+
+ break;
+
+ case ACL_EXPR_TYPE_RESPONSE:
+ (void) ACL_ExprGetDenyWith(NULL, ace, &cache->deny_type,
+ &cache->deny_response);
+ break;
+
+ default:
+ NS_ASSERT(0);
+
+ } /* switch expr_type */
+
+ new_ace->global_auth = curauthplist;
+ ace = ace->expr_next;
+ }
+
+ /* Next ACL please */
+ wrapper = wrapper->wrap_next;
+ }
+
+ if (absauthplist)
+ PListDestroy(absauthplist);
+
+ /* This must be done last to avoid a race in initialization */
+ acleval->acllist->cache = (void *)cache;
+
+ return 0;
+
+error:
+ if (absauthplist)
+ PListDestroy(absauthplist);
+ if (cache) {
+ ACL_EvalDestroyContext(cache);
+ }
+ acleval->acllist->cache = NULL;
+ return ACL_RES_ERROR;
+}
+
+/* ACL_InvalidateSubjectPList
+ * Given a new authentication plist, enumerate the plist and for each
+ * key in the plist, search for the matching key in the subject plist
+ * and delete any matches. E.g. "user", "group".
+ */
+void
+ACL_InvalidateSubjectPList(char *attr, const void *value, void *user_data)
+{
+ PList_t subject = (PList_t)user_data;
+
+ PListDeleteProp(subject, 0, attr);
+ return;
+}
+
+NSAPI_PUBLIC int ACL_SetDefaultResult (NSErr_t *errp,
+ ACLEvalHandle_t *acleval,
+ int result)
+{
+ int rv;
+
+ switch(result) {
+ case ACL_RES_ALLOW:
+ case ACL_RES_DENY:
+ case ACL_RES_FAIL:
+ case ACL_RES_INVALID:
+ acleval->default_result = result;
+ rv = 0;
+ break;
+ default:
+ rv = -1;
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ACL_GetDefaultResult (ACLEvalHandle_t *acleval)
+{
+ return acleval->default_result;
+}
+
+/* ACL_INTEvalTestRights
+ * INPUT
+ * *errp The usual error context stack
+ * *acleval A list of ACLs
+ * **rights An array of strings listing the requested rights
+ * **map_generic An array of strings listing the specific rights
+ * that map from the generic rights.
+ * OUTPUT
+ * **deny_type bong file type passed on the way back out
+ * **deny_response bong file pathname passed on the way back out
+ * **acl_tag Name of the ACL that denies access
+ * *expr_num ACE number within the denying ACL
+ * *cachable Is the result cachable?
+ */
+static int
+ACL_INTEvalTestRights(
+ NSErr_t *errp,
+ ACLEvalHandle_t *acleval,
+ char **rights,
+ char **map_generic,
+ char **deny_type,
+ char **deny_response,
+ char **acl_tag,
+ int *expr_num,
+ ACLCachable_t *cachable)
+{
+ struct rights_ent {
+ char right[64]; /* lowercase-ed rights string */
+ int result; /* Interim result value */
+ int absolute; /* ACE with absolute keyword */
+ int count; /* # specific + generic rights */
+ ACLAceNumEntry_t *acelist[ACL_MAX_GENERIC+1];
+ /* List of relevant ACEs */
+ };
+ struct rights_ent *rarray_p;
+ struct rights_ent rights_arry[ACL_MAX_TEST_RIGHTS];
+ ACLAceNumEntry_t *alllist; /* List of ACEs for "all" rights */
+ ACLAceEntry_t *cur_ace;
+ ACLListCache_t *cache;
+ int rights_cnt = 0;
+ int prev_acenum, cur_acenum;
+ int i, j, right_num, delta;
+ ACLCachable_t ace_cachable;
+ int result;
+ int absolute;
+ int skipflag;
+ int g_num; /* index into the generic rights array. */
+ char **g_rights;
+ PList_t global_auth=NULL;
+ int allow_error = 0;
+ int allow_absolute = 0;
+ char *allow_tag = NULL;
+ int allow_num = 0;
+ int default_result = ACL_GetDefaultResult(acleval);
+
+ *acl_tag = NULL;
+ *expr_num = 0;
+ *cachable = ACL_INDEF_CACHABLE;
+
+ /*
+ * The acleval contains the list of acis we are asking about.
+ * In our case it's always of length 1.
+ * The acleval is a per aclpb structure but
+ * the acllist is a global structure derived from the global
+ * aci cache--so access to acllist is multi-threaded.
+ * Hence, for example the use of the "read-only" hash
+ * lookup routines in this function--ACL_EvalTestRights()
+ * is called in a "reader only context" so this code is therefore
+ * thread-safe.
+ */
+
+ if (acleval->acllist == ACL_LIST_NO_ACLS) return ACL_RES_ALLOW;
+
+ /* Build up the access right - indexed structures */
+ if (acleval->acllist->cache == NULL) {
+ ACL_CritEnter();
+ if (acleval->acllist->cache == NULL) { /* Check again */
+ if (ACLEvalBuildContext(errp, acleval) == ACL_RES_ERROR) {
+ nserrGenerate(errp, ACLERRINTERNAL, ACLERR4110, ACL_Program,
+ 1, XP_GetAdminStr(DBT_EvalTestRightsEvalBuildContextFailed));
+ ACL_CritExit();
+ return ACL_RES_ERROR;
+ }
+ }
+ ACL_CritExit();
+ }
+ cache = (ACLListCache_t *)acleval->acllist->cache;
+ *deny_response = cache->deny_response;
+ *deny_type = cache->deny_type;
+
+ /* For the list of rights requested, get back the list of relevant
+ * ACEs. If we want
+ * to alter the precedence of allow/deny, this would be a good
+ * place to do it.
+ */
+
+ while (*rights)
+ {
+ rarray_p = &rights_arry[rights_cnt];
+
+ /* Initialize the rights array entry */
+ strcpy(&rarray_p->right[0], *rights);
+ makelower(&rarray_p->right[0]);
+ rarray_p->result = default_result;
+ rarray_p->absolute = 0;
+ rarray_p->count = 1; // There's always the specific right
+
+ /* Locate the list of ACEs that apply to the right */
+ rarray_p->acelist[0] =
+ (ACLAceNumEntry_t *)ACL_HashTableLookup_const(cache->Table, rarray_p->right);
+
+ /* See if the requested right also maps back to a generic right and
+ * if so, locate the acelist for it as well.
+ */
+ if (map_generic)
+ {
+ for (g_rights=map_generic, g_num=0; *g_rights; g_rights++, g_num++)
+ {
+ if (strstr(*g_rights, rarray_p->right)) {
+ // Add it to our acelist, but skip 0 'cause that's the
+ // specific right.
+ rarray_p->acelist[rarray_p->count++] =
+ (ACLAceNumEntry_t *)ACL_HashTableLookup_const(cache->Table,
+ (char *)generic_rights[g_num]);
+ NS_ASSERT (rarray_p->count < ACL_MAX_GENERIC);
+ }
+ }
+ }
+
+ rights_cnt++;
+ rights++;
+ NS_ASSERT (rights_cnt < ACL_MAX_TEST_RIGHTS);
+ }
+
+ /* Special case - look for an entry that applies to "all" rights */
+ alllist = (ACLAceNumEntry_t *)ACL_HashTableLookup_const(cache->Table, "all");
+
+ /* Ok, we've now got a list of relevant ACEs. Now evaluate things. */
+ prev_acenum = -1;
+ cur_ace = cache->acelist;
+
+ /* Loop through the relevant ACEs for the requested rights */
+ while (TRUE)
+ {
+ cur_acenum = 10000; /* Pick a really high num so we lose */
+ /* Find the lowest ACE among the rights lists */
+ for (i=0; i<rights_cnt; i++) {
+ rarray_p = &rights_arry[i];
+ if (rarray_p->absolute) continue; // This right doesn't matter
+ for (j=0; j<rarray_p->count; j++) {
+ if ((rarray_p->acelist[j] != NULL) &&
+ (rarray_p->acelist[j]->acenum < cur_acenum)) {
+ cur_acenum = rarray_p->acelist[j]->acenum;
+ }
+ }
+ }
+
+ /* Special case - look for the "all" rights ace list and see if its
+ * the lowest of all.
+ */
+ if (alllist && (alllist->acenum < cur_acenum))
+ cur_acenum = alllist->acenum;
+
+ /* If no new ACEs then we're done - evaluate the rights list */
+ if (cur_acenum == 10000)
+ break;
+
+ /* Locate that ACE and evaluate it. We have to step through the
+ * linked list of ACEs to find it.
+ */
+ if (prev_acenum == -1)
+ delta = cur_acenum;
+ else
+ delta = cur_acenum - prev_acenum;
+
+ for (i=0; i<delta; i++)
+ cur_ace = cur_ace->next;
+
+ if (global_auth && global_auth != cur_ace->global_auth) {
+ /* We must enumerate the auth_info plist and remove entries for
+ * each attribute from the subject property list.
+ */
+ PListEnumerate(cur_ace->global_auth, ACL_InvalidateSubjectPList,
+ acleval->subject);
+ }
+ global_auth = cur_ace->global_auth;
+
+ result = ACLEvalAce(errp, acleval, cur_ace->acep, &ace_cachable,
+ cur_ace->autharray, cur_ace->global_auth);
+
+ /* Evaluate the cachable value */
+ if (ace_cachable < *cachable) {
+ /* Take the minimum value */
+ *cachable = ace_cachable;
+ }
+
+ /* Under certain circumstances, no matter what happens later,
+ * the current result is not gonna change.
+ */
+ if ((result != LAS_EVAL_TRUE) && (result != LAS_EVAL_FALSE)) {
+ if (cur_ace->acep->expr_type != ACL_EXPR_TYPE_ALLOW) {
+ if (allow_error) {
+ *acl_tag = allow_tag;
+ *expr_num = allow_num;
+ return (allow_error);
+ } else {
+ *acl_tag = cur_ace->acep->acl_tag;
+ *expr_num = cur_ace->acep->expr_number;
+ return (EvalToRes(result));
+ }
+ } else {
+ /* If the error is on an allow statement, continue processing
+ * and see if a subsequent allow works. If not, remember the
+ * error and return it.
+ */
+ if (!allow_error) {
+ allow_error = EvalToRes(result);
+ allow_tag = cur_ace->acep->acl_tag;
+ allow_num = cur_ace->acep->expr_number;
+ }
+ if (IS_ABSOLUTE(cur_ace->acep->expr_flags)) {
+ allow_absolute = 1;
+ }
+ }
+ }
+
+ /* Now apply the result to the rights array. Look to see which rights'
+ * acelist include the current one, or if the current one is on the
+ * "all" rights ace list.
+ */
+ for (right_num=0; right_num<rights_cnt; right_num++)
+ {
+ rarray_p = &rights_arry[right_num];
+
+ /* Have we fixated on a prior result? */
+ if (rarray_p->absolute)
+ continue;
+
+ skipflag = 1;
+
+ // Did this ace apply to this right?
+ for (i=0; i<rarray_p->count; i++) {
+ if ((rarray_p->acelist[i]) &&
+ (rarray_p->acelist[i]->acenum == cur_acenum)) {
+ rarray_p->acelist[i] = rarray_p->acelist[i]->next;
+ skipflag = 0;
+ }
+ }
+
+ /* This ace was on the "all" rights queue */
+ if ((alllist) && (alllist->acenum == cur_acenum)) {
+ skipflag = 0;
+ }
+
+ if (skipflag)
+ continue; /* doesn't apply to this right */
+
+ if (IS_ABSOLUTE(cur_ace->acep->expr_flags) && (result ==
+ LAS_EVAL_TRUE)) {
+ rarray_p->absolute = 1;
+ absolute = 1;
+ } else
+ absolute = 0;
+
+ switch (cur_ace->acep->expr_type) {
+ case ACL_EXPR_TYPE_ALLOW:
+ if (result == LAS_EVAL_TRUE) {
+ rarray_p->result = ACL_RES_ALLOW;
+ if (!allow_absolute) {
+ /* A previous ALLOW error was superceded */
+ allow_error = 0;
+ }
+ }
+ else if (!*acl_tag) {
+ *acl_tag = cur_ace->acep->acl_tag;
+ *expr_num = cur_ace->acep->expr_number;
+ }
+ break;
+ case ACL_EXPR_TYPE_DENY:
+ if (result == LAS_EVAL_TRUE) {
+ *acl_tag = cur_ace->acep->acl_tag;
+ *expr_num = cur_ace->acep->expr_number;
+ if (absolute) {
+ if (allow_error) {
+ *acl_tag = allow_tag;
+ *expr_num = allow_num;
+ return (allow_error);
+ }
+ return (ACL_RES_DENY);
+ }
+ rarray_p->result = ACL_RES_DENY;
+ }
+ break;
+ default:
+ /* a non-authorization ACE, just ignore */
+ break;
+ }
+
+ }
+
+ /* This ace was on the "all" rights queue */
+ if ((alllist) && (alllist->acenum == cur_acenum)) {
+ alllist = alllist->next;
+ }
+
+ /* If this is an absolute, check to see if all the rights
+ * have already been fixed by this or previous absolute
+ * statements. If so, we can compute the response without
+ * evaluating any more of the ACL list.
+ */
+ if (absolute) {
+ for (i=0; i<rights_cnt; i++) {
+ /* Non absolute right, so skip this section */
+ if (rights_arry[i].absolute == 0)
+ break;
+ /* This shouldn't be possible, but check anyway.
+ * Any absolute non-allow result should already
+ * have been returned earlier.
+ */
+ if (rights_arry[i].result != ACL_RES_ALLOW) {
+ char result_str[16];
+ sprintf(result_str, "%d", rights_arry[i].result);
+ nserrGenerate(errp, ACLERRINTERNAL, ACLERR4100, ACL_Program, 3, XP_GetAdminStr(DBT_EvalTestRightsInterimAbsoluteNonAllowValue), rights[i], result_str);
+ break;
+ }
+ if (i == (rights_cnt - 1))
+ return ACL_RES_ALLOW;
+ }
+ }
+
+ prev_acenum = cur_acenum;
+
+ } /* Next ACE */
+
+ /* Do an AND on the results for the individual rights */
+ for (right_num=0; right_num<rights_cnt; right_num++)
+ if (rights_arry[right_num].result != ACL_RES_ALLOW) {
+ if (allow_error) {
+ *acl_tag = allow_tag;
+ *expr_num = allow_num;
+ return (allow_error);
+ }
+ return (rights_arry[right_num].result);
+ }
+
+ return (ACL_RES_ALLOW);
+
+}
+
+
+/* ACL_CachableAclList
+ * Returns 1 if the ACL list will always evaluate to ALLOW for http_get.
+ */
+NSAPI_PUBLIC int
+ACL_CachableAclList(ACLListHandle_t *acllist)
+{
+ ACLEvalHandle_t *acleval;
+ char *bong;
+ char *bong_type;
+ char *acl_tag;
+ int expr_num;
+ int rv;
+ static char *rights[] = { "http_get", NULL };
+ ACLCachable_t cachable=ACL_INDEF_CACHABLE;
+
+ if (!acllist || acllist == ACL_LIST_NO_ACLS) {
+ return 1;
+ }
+ acleval = ACL_EvalNew(NULL, NULL);
+ ACL_EvalSetACL(NULL, acleval, acllist);
+ rv = ACL_INTEvalTestRights(NULL, acleval, rights, http_generic,
+ &bong_type, &bong, &acl_tag, &expr_num,
+ &cachable);
+
+ ACL_EvalDestroyNoDecrement(NULL, NULL, acleval);
+ if (rv == ACL_RES_ALLOW && cachable == ACL_INDEF_CACHABLE) {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+NSAPI_PUBLIC int
+ACL_EvalTestRights(
+ NSErr_t *errp,
+ ACLEvalHandle_t *acleval,
+ char **rights,
+ char **map_generic,
+ char **deny_type,
+ char **deny_response,
+ char **acl_tag,
+ int *expr_num)
+{
+ ACLCachable_t cachable;
+
+ return (ACL_INTEvalTestRights(errp, acleval, rights, map_generic,
+ deny_type, deny_response,
+ acl_tag, expr_num, &cachable));
+}
+
+
+NSAPI_PUBLIC ACLEvalHandle_t *
+ACL_EvalNew(NSErr_t *errp, pool_handle_t *pool)
+{
+ ACLEvalHandle_t *rv = ((ACLEvalHandle_t *)pool_calloc(pool, sizeof(ACLEvalHandle_t), 1));
+ rv->default_result = ACL_RES_DENY;
+ return rv;
+}
+
+NSAPI_PUBLIC void
+ACL_EvalDestroy(NSErr_t *errp, pool_handle_t *pool, ACLEvalHandle_t *acleval)
+{
+ if (!acleval->acllist || acleval->acllist == ACL_LIST_NO_ACLS)
+ return;
+ NS_ASSERT(acleval->acllist->ref_count > 0);
+
+ ACL_CritEnter();
+ NS_ASSERT(ACL_CritHeld());
+ if (--acleval->acllist->ref_count == 0) {
+ if (ACL_LIST_IS_STALE(acleval->acllist)) {
+ ACL_ListDestroy(errp, acleval->acllist);
+ }
+ }
+ ACL_CritExit();
+ pool_free(pool, acleval);
+}
+
+NSAPI_PUBLIC void
+ACL_EvalDestroyNoDecrement(NSErr_t *errp, pool_handle_t *pool, ACLEvalHandle_t *acleval)
+{
+ /*if (!acleval->acllist || acleval->acllist == ACL_LIST_NO_ACLS)
+ return; */
+
+ /* olga: we need to free acleval unconditionally to avoid memory leaks */
+ if (acleval)
+ pool_free(pool, acleval);
+}
+
+NSAPI_PUBLIC int
+ACL_ListDecrement(NSErr_t *errp, ACLListHandle_t *acllist)
+{
+ if (!acllist || acllist == ACL_LIST_NO_ACLS)
+ return 0;
+
+ NS_ASSERT(ACL_AssertAcllist(acllist));
+
+ ACL_CritEnter();
+ NS_ASSERT(ACL_CritHeld());
+ if (--acllist->ref_count == 0) {
+ if (ACL_LIST_IS_STALE(acllist)) {
+ ACL_ListDestroy(errp, acllist);
+ }
+ }
+ ACL_CritExit();
+
+ return 0;
+}
+
+NSAPI_PUBLIC int
+ACL_EvalSetACL(NSErr_t *errp, ACLEvalHandle_t *acleval, ACLListHandle_t *acllist)
+{
+ NS_ASSERT(ACL_AssertAcllist(acllist));
+
+ acleval->acllist = acllist;
+ return(0);
+}
+
+NSAPI_PUBLIC int
+ACL_EvalSetSubject(NSErr_t *errp, ACLEvalHandle_t *acleval, PList_t subject)
+{
+ acleval->subject = subject;
+ return 0;
+}
+
+NSAPI_PUBLIC PList_t
+ACL_EvalGetSubject(NSErr_t *errp, ACLEvalHandle_t *acleval)
+{
+ return (acleval->subject);
+}
+
+NSAPI_PUBLIC int
+ACL_EvalSetResource(NSErr_t *errp, ACLEvalHandle_t *acleval, PList_t resource)
+{
+ acleval->resource = resource;
+ return 0;
+}
+
+NSAPI_PUBLIC PList_t
+ACL_EvalGetResource(NSErr_t *errp, ACLEvalHandle_t *acleval)
+{
+ return (acleval->resource);
+}
diff --git a/lib/libaccess/oneeval.h b/lib/libaccess/oneeval.h
new file mode 100644
index 00000000..022570dd
--- /dev/null
+++ b/lib/libaccess/oneeval.h
@@ -0,0 +1,17 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef LEVAL_H
+#define LEVAL_H
+
+NSPR_BEGIN_EXTERN_C
+
+int
+freeLAS(NSErr_t *errp, char *attribute, void **las_cookie);
+
+NSPR_END_EXTERN_C
+
+#endif
+
diff --git a/lib/libaccess/parse.h b/lib/libaccess/parse.h
new file mode 100644
index 00000000..420bd913
--- /dev/null
+++ b/lib/libaccess/parse.h
@@ -0,0 +1,21 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * module private routines for handling the yacc based
+ * ACL Parser.
+ */
+
+#ifndef PARSE_H
+#define PARSE_H
+
+NSPR_BEGIN_EXTERN_C
+
+extern int acl_PushListHandle(ACLListHandle_t *handle);
+extern int acl_Parse(void);
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/permhash.h b/lib/libaccess/permhash.h
new file mode 100644
index 00000000..f072be2b
--- /dev/null
+++ b/lib/libaccess/permhash.h
@@ -0,0 +1,79 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _PERMHASH_H_
+#define _PERMHASH_H_
+
+#include <string.h>
+#include <plhash.h>
+#include <base/pool.h>
+#include <base/util.h>
+
+static void *
+ACL_PermAllocTable(void *pool, PRSize size)
+{
+ return pool_malloc((pool_handle_t *)pool, size);
+}
+
+static void
+ACL_PermFreeTable(void *pool, void *item)
+{
+ pool_free((pool_handle_t *)pool, item);
+}
+
+static PLHashEntry *
+ACL_PermAllocEntry(void *pool, const void *unused)
+{
+ return ((PLHashEntry *)pool_malloc((pool_handle_t *)pool, sizeof(PLHashEntry)));
+}
+
+static void
+ACL_PermFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
+{
+ if (flag == HT_FREE_ENTRY)
+ pool_free((pool_handle_t *)pool, he);
+}
+
+static PLHashAllocOps ACLPermAllocOps = {
+ ACL_PermAllocTable,
+ ACL_PermFreeTable,
+ ACL_PermAllocEntry,
+ ACL_PermFreeEntry
+};
+
+static int
+PR_StringFree(PLHashEntry *he, int i, void *arg)
+{
+ PERM_FREE(he->key);
+ return 0;
+}
+
+static PLHashNumber
+PR_HashCaseString(const void *key)
+{
+ PLHashNumber h;
+ const unsigned char *s;
+
+ h = 0;
+ for (s = (const unsigned char *)key; *s; s++)
+ h = (h >> 28) ^ (h << 4) ^ tolower(*s);
+ return h;
+}
+
+static int
+PR_CompareCaseStrings(const void *v1, const void *v2)
+{
+ const char *s1 = (const char *)v1;
+ const char *s2 = (const char *)v2;
+
+#ifdef XP_WIN32
+ return (util_strcasecmp(s1, s2) == 0);
+#else
+ return (strcasecmp(s1, s2) == 0);
+#endif
+}
+
+
+#endif /* _PERMHASH_H */
diff --git a/lib/libaccess/register.cpp b/lib/libaccess/register.cpp
new file mode 100644
index 00000000..2973e1d5
--- /dev/null
+++ b/lib/libaccess/register.cpp
@@ -0,0 +1,821 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * LAS registration interface
+ */
+
+#include <netsite.h>
+#include <plhash.h>
+#include <base/systems.h>
+#include <base/util.h>
+#include <base/nsassert.h>
+#include "permhash.h"
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/aclglobal.h>
+#include <libaccess/ldapacl.h>
+#include "aclcache.h"
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+
+/* This is to force aclspace.o into ns-httpd30.dll */
+static ACLGlobal_p *link_ACLGlobal = &ACLGlobal;
+
+/* This forces oneeval.o into ns-httpd30.dll */
+static ACLDispatchVector_t **link_nsacl_table = &__nsacl_table;
+
+ACLMethod_t ACLMethodDefault = ACL_METHOD_INVALID;
+ACLDbType_t ACLDbTypeDefault = ACL_DBTYPE_INVALID;
+static char *ACLDatabaseDefault = 0;
+
+ACLDbType_t ACL_DbTypeLdap = ACL_DBTYPE_INVALID;
+
+DbParseFn_t ACLDbParseFnTable[ACL_MAX_DBTYPE];
+
+void
+ACL_LasHashInit()
+{
+ int i;
+
+ ACLLasEvalHash = PR_NewHashTable(0,
+ PR_HashString,
+ PR_CompareStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ NS_ASSERT(ACLLasEvalHash);
+
+ ACLLasFlushHash = PR_NewHashTable(0,
+ PR_HashString,
+ PR_CompareStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ NS_ASSERT(ACLLasFlushHash);
+
+ ACLMethodHash = PR_NewHashTable(ACL_MAX_METHOD,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ NS_ASSERT(ACLMethodHash);
+
+ ACLDbTypeHash = PR_NewHashTable(ACL_MAX_DBTYPE,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ NS_ASSERT(ACLDbTypeHash);
+
+ for (i = 0; i < ACL_MAX_DBTYPE; i++)
+ ACLDbParseFnTable[i] = 0;
+
+ ACLAttrGetterHash = PR_NewHashTable(256,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ NS_ASSERT(ACLDbTypeHash);
+
+ ACLDbNameHash = PR_NewHashTable(0,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ ACL_DATABASE_POOL);
+ NS_ASSERT(ACLDbNameHash);
+
+ ACLUserLdbHash = PR_NewHashTable(0,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ NS_ASSERT(ACLUserLdbHash);
+
+ return;
+}
+
+void
+ACL_LasHashDestroy()
+{
+ if (ACLLasEvalHash) {
+ PR_HashTableDestroy(ACLLasEvalHash);
+ ACLLasEvalHash=NULL;
+ }
+ if (ACLLasFlushHash) {
+ PR_HashTableDestroy(ACLLasFlushHash);
+ ACLLasFlushHash=NULL;
+ }
+}
+
+/* ACL_LasRegister
+ * INPUT
+ * errp NSError structure
+ * attr_name E.g. "ip" or "dns" etc.
+ * eval_func E.g. LASIpEval
+ * flush_func Optional - E.g. LASIpFlush or NULL
+ * OUTPUT
+ * 0 on success, non-zero on failure
+ */
+NSAPI_PUBLIC int
+ACL_LasRegister(NSErr_t *errp, char *attr_name, LASEvalFunc_t eval_func,
+LASFlushFunc_t flush_func)
+{
+
+ if ((!attr_name) || (!eval_func)) return -1;
+
+ ACL_CritEnter();
+
+ /* See if the function is already registered. If so, report and
+ * error, but go ahead and replace it.
+ */
+ if (PR_HashTableLookup(ACLLasEvalHash, attr_name) != NULL) {
+ nserrGenerate(errp, ACLERRDUPSYM, ACLERR3900, ACL_Program, 1,
+ attr_name);
+ }
+
+ /* Put it in the hash tables */
+ PR_HashTableAdd(ACLLasEvalHash, attr_name, (void *)eval_func);
+ PR_HashTableAdd(ACLLasFlushHash, attr_name, (void *)flush_func);
+
+ ACL_CritExit();
+ return 0;
+}
+
+/* ACL_LasFindEval
+ * INPUT
+ * errp NSError pointer
+ * attr_name E.g. "ip" or "user" etc.
+ * eval_funcp Where the function pointer is returned. NULL if the
+ * function isn't registered.
+ * Must be called in a critical section as ACLEvalHash is a global
+ * variable.
+ * OUTPUT
+ * 0 on success, non-zero on failure
+ */
+NSAPI_PUBLIC int
+ACL_LasFindEval(NSErr_t *errp, char *attr_name, LASEvalFunc_t *eval_funcp)
+{
+
+ NS_ASSERT(attr_name);
+ if (!attr_name) return -1;
+
+ *eval_funcp = (LASEvalFunc_t)PR_HashTableLookup(ACLLasEvalHash, attr_name);
+ return 0;
+}
+
+
+/* ACL_LasFindFlush
+ * INPUT
+ * errp NSError pointer
+ * attr_name E.g. "ip" or "user" etc.
+ * eval_funcp Where the function pointer is returned. NULL if the
+ * function isn't registered.
+ * OUTPUT
+ * 0 on success, non-zero on failure
+ */
+NSAPI_PUBLIC int
+ACL_LasFindFlush(NSErr_t *errp, char *attr_name, LASFlushFunc_t *flush_funcp)
+{
+
+ NS_ASSERT(attr_name);
+ if (!attr_name) return -1;
+
+ *flush_funcp = (LASFlushFunc_t)PR_HashTableLookup(ACLLasFlushHash, attr_name);
+ return 0;
+}
+
+
+/* ACL_MethodRegister
+ * INPUT
+ * name Method name string. Can be freed after return.
+ * OUTPUT
+ * &t Place to return the Method_t (>0)
+ * retcode 0 on success, non-zero otherwise
+ */
+
+int cur_method = 0; /* Use a static counter to generate the numbers */
+
+NSAPI_PUBLIC int
+ACL_MethodRegister(NSErr_t *errp, const char *name, ACLMethod_t *t)
+{
+ ACLMethod_t rv;
+
+ ACL_CritEnter();
+
+ /* See if this is already registered */
+ rv = (ACLMethod_t) PR_HashTableLookup(ACLMethodHash, name);
+ if (rv != NULL) {
+ *t = rv;
+ ACL_CritExit();
+ return 0;
+ }
+
+ /* To prevent the hash table from resizing, don't get to 32 entries */
+ if (cur_method >= (ACL_MAX_METHOD-1)) {
+ ACL_CritExit();
+ return -1;
+ }
+
+ /* Put it in the hash table */
+ rv = PR_HashTableAdd(ACLMethodHash, name, (void *)++cur_method);
+ *t = (ACLMethod_t) cur_method;
+
+ ACL_CritExit();
+ return 0;
+}
+
+NSAPI_PUBLIC int
+ACL_MethodFind(NSErr_t *errp, const char *name, ACLMethod_t *t)
+{
+ ACLMethod_t rv;
+
+ /* Don't have to get the Critical Section lock 'cause the only danger
+ * would be if the hash table had to be resized. We created it with
+ * room for 32 entries before that happens.
+ */
+ rv = (ACLMethod_t) PR_HashTableLookup(ACLMethodHash, name);
+ if (rv != NULL) {
+ *t = rv;
+ return 0;
+ }
+
+ return -1;
+}
+
+typedef struct HashEnumArg_s {
+ char **names;
+ int count;
+} HashEnumArg_t;
+
+typedef HashEnumArg_t *HashEnumArg_p;
+
+static int acl_hash_enumerator (PLHashEntry *he, PRIntn i, void *arg)
+{
+ HashEnumArg_t *info = (HashEnumArg_t *)arg;
+ char **names = info->names;
+
+ names[info->count++] = STRDUP((const char *)he->key);
+
+ return names[info->count-1] ? 0 : -1;
+}
+
+int acl_registered_names(PLHashTable *ht, int count, char ***names)
+{
+ HashEnumArg_t arg;
+ int rv;
+
+ if (count == 0) {
+ *names = 0;
+ return 0;
+ }
+
+ arg.names = (char **)MALLOC(count * sizeof(char *));
+ arg.count = 0;
+
+ if (!arg.names) return -1;
+
+ rv = PR_HashTableEnumerateEntries(ht, acl_hash_enumerator, &arg);
+
+ if (rv >= 0) {
+ /* success */
+ *names = arg.names;
+ }
+ else {
+ *names = 0;
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC int
+ACL_MethodNamesGet(NSErr_t *errp, char ***names, int *count)
+{
+ *count = cur_method;
+ return acl_registered_names (ACLMethodHash, *count, names);
+}
+
+NSAPI_PUBLIC int
+ACL_MethodNamesFree(NSErr_t *errp, char **names, int count)
+{
+ int i;
+
+ if (!names) return 0;
+
+ for (i = count-1; i; i--) FREE(names[i]);
+
+ FREE(names);
+ return 0;
+}
+
+NSAPI_PUBLIC int
+ACL_DbTypeFind(NSErr_t *errp, const char *name, ACLDbType_t *t)
+{
+ ACLDbType_t rv;
+
+ /* Don't have to get the Critical Section lock 'cause the only danger
+ * would be if the hash table had to be resized. We created it with
+ * room for 32 entries before that happens.
+ */
+ rv = (ACLDbType_t) PR_HashTableLookup(ACLDbTypeHash, name);
+ if (rv != NULL) {
+ *t = rv;
+ return 0;
+ }
+
+ return -1;
+}
+
+/* ACL_DbTypeRegister
+ * INPUT
+ * name DbType name string. Can be freed after return.
+ * OUTPUT
+ * &t Place to return the DbType (>0)
+ * retcode 0 on success, non-zero otherwise
+ */
+
+int cur_dbtype = 0; /* Use a static counter to generate the numbers */
+
+NSAPI_PUBLIC int
+ACL_DbTypeRegister(NSErr_t *errp, const char *name, DbParseFn_t func, ACLDbType_t *t)
+{
+ ACLDbType_t rv;
+
+ ACL_CritEnter();
+
+ /* See if this is already registered */
+ rv = (ACLDbType_t) PR_HashTableLookup(ACLDbTypeHash, name);
+ if (rv != NULL) {
+ *t = rv;
+ ACLDbParseFnTable[(int)(PRSize)rv] = func;
+ ACL_CritExit();
+ return 0;
+ }
+
+ /* To prevent the hash table from resizing, don't get to 32 entries */
+ if (cur_dbtype >= (ACL_MAX_DBTYPE-1)) {
+ ACL_CritExit();
+ return -1;
+ }
+
+ /* Put it in the hash table */
+ rv = PR_HashTableAdd(ACLDbTypeHash, name, (void *)++cur_dbtype);
+ *t = (ACLDbType_t) cur_dbtype;
+ ACLDbParseFnTable[cur_dbtype] = func;
+
+ ACL_CritExit();
+ return 0;
+}
+
+
+NSAPI_PUBLIC int
+ACL_DbTypeIsRegistered (NSErr_t *errp, const ACLDbType_t t)
+{
+ return (0 < ((int)(PRSize)t) && ((int)(PRSize)t) <= cur_dbtype);
+}
+
+
+/* ACL_MethodIsEqual
+ * RETURNS non-zero if equal.
+ */
+NSAPI_PUBLIC int
+ACL_MethodIsEqual(NSErr_t *errp, const ACLMethod_t t1, const ACLMethod_t t2)
+{
+ return (t1 == t2);
+}
+
+
+/* ACL_DbTypeIsEqual
+ * RETURNS non-zero if equal.
+ */
+NSAPI_PUBLIC int
+ACL_DbTypeIsEqual(NSErr_t *errp, const ACLDbType_t t1, const ACLDbType_t t2)
+{
+ return (t1 == t2);
+}
+
+
+/* ACL_MethodNameIsEqual
+ * Takes a method type and a method name and sees if they match.
+ * Returns non-zero on match.
+ */
+NSAPI_PUBLIC int
+ACL_MethodNameIsEqual(NSErr_t *errp, const ACLMethod_t t1, const char *name)
+{
+ int rv;
+ ACLMethod_t t2;
+
+ rv = ACL_MethodFind(errp, name, &t2);
+ if (rv)
+ return (rv);
+ else
+ return (t1 == t2);
+}
+
+/* ACL_DbTypeNameIsEqual
+ * Takes a dbtype type and a dbtype name and sees if they match.
+ * Returns non-zero on match.
+ */
+NSAPI_PUBLIC int
+ACL_DbTypeNameIsEqual(NSErr_t *errp, const ACLDbType_t t1, const char *name)
+{
+ int rv;
+ ACLDbType_t t2;
+
+ rv = ACL_DbTypeFind(errp, name, &t2);
+ if (rv)
+ return (rv);
+ else
+ return (t1 == t2);
+}
+
+/* ACL_MethodGetDefault
+ */
+NSAPI_PUBLIC ACLMethod_t
+ACL_MethodGetDefault(NSErr_t *errp)
+{
+ return (ACLMethodDefault);
+}
+
+/* ACL_MethodSetDefault
+ */
+NSAPI_PUBLIC int
+ACL_MethodSetDefault(NSErr_t *errp, const ACLMethod_t t)
+{
+ ACLMethodDefault = t;
+ return 0;
+}
+
+
+/* ACL_DbTypeGetDefault
+ */
+NSAPI_PUBLIC ACLDbType_t
+ACL_DbTypeGetDefault(NSErr_t *errp)
+{
+ return (ACLDbTypeDefault);
+}
+
+/* ACL_DbTypeSetDefault
+ */
+NSAPI_PUBLIC int
+ACL_DbTypeSetDefault(NSErr_t *errp, ACLDbType_t t)
+{
+ ACLDbTypeDefault = t;
+ return 0;
+}
+
+
+/* ACL_DatabaseGetDefault
+ */
+NSAPI_PUBLIC const char *
+ACL_DatabaseGetDefault(NSErr_t *errp)
+{
+ return (ACLDatabaseDefault);
+}
+
+/* ACL_DatabaseSetDefault
+ */
+NSAPI_PUBLIC int
+ACL_DatabaseSetDefault(NSErr_t *errp, const char *dbname)
+{
+ ACLDbType_t dbtype;
+ int rv;
+ void *db;
+
+ if (!dbname || !*dbname) return LAS_EVAL_FAIL;
+
+ rv = ACL_DatabaseFind(errp, dbname, &dbtype, &db);
+
+ if (rv != LAS_EVAL_TRUE) return -1;
+
+ if (ACLDatabaseDefault) pool_free(ACL_DATABASE_POOL, ACLDatabaseDefault);
+
+ ACL_DbTypeSetDefault(errp, dbtype);
+ ACLDatabaseDefault = pool_strdup(ACL_DATABASE_POOL, dbname);
+
+ return ACLDatabaseDefault ? 0 : -1;
+}
+
+
+/* ACL_AuthInfoGetMethod
+ * INPUT
+ * auth_info A PList of the authentication name/value pairs as
+ * provided by EvalTestRights to the LAS.
+ * OUTPUT
+ * *t The Method number. This can be the default method
+ number if the auth_info PList doesn't explicitly have a Method entry.
+ * retcode 0 on success.
+ */
+NSAPI_PUBLIC int
+ACL_AuthInfoGetMethod(NSErr_t *errp, PList_t auth_info, ACLMethod_t *t)
+{
+ ACLMethod_t *methodp;
+
+ if (!auth_info ||
+ PListGetValue(auth_info, ACL_ATTR_METHOD_INDEX, (void **)&methodp, NULL) < 0)
+ {
+ /* No entry for "method" */
+ *t = ACLMethodDefault;
+ } else {
+ *t = *methodp;
+ }
+
+ return 0;
+}
+
+
+/* ACL_AuthInfoSetMethod
+ * INPUT
+ * auth_info A PList of the authentication name/value pairs as
+ * provided by EvalTestRights to the LAS.
+ * t The Method number.
+ * OUTPUT
+ * retcode 0 on success.
+ */
+NSAPI_PUBLIC int
+ACL_AuthInfoSetMethod(NSErr_t *errp, PList_t auth_info, ACLMethod_t t)
+{
+ ACLMethod_t *methodp;
+ int rv;
+
+ if (auth_info) {
+ rv = PListGetValue(auth_info, ACL_ATTR_METHOD_INDEX, (void **)&methodp,
+ NULL);
+
+ if (rv < 0) {
+ /* No entry for "method" */
+ methodp = (ACLMethod_t *)PERM_MALLOC(sizeof(ACLMethod_t));
+ if (!methodp) return -1;
+ *methodp = t;
+ PListInitProp(auth_info, ACL_ATTR_METHOD_INDEX, ACL_ATTR_METHOD, methodp, 0);
+ }
+ else {
+ /* replace the old entry */
+ if (!methodp) return -1;
+ *methodp = t;
+ }
+ }
+ else {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* ACL_AuthInfoSetDbname
+ * INPUT
+ * auth_info A PList of the authentication name/value pairs as
+ * provided by EvalTestRights to the LAS.
+ * dbname Name of the new auth_info database.
+ * OUTPUT
+ * retcode 0 on success.
+ */
+NSAPI_PUBLIC int
+ACL_AuthInfoSetDbname(NSErr_t *errp, PList_t auth_info, const char *dbname)
+{
+ ACLDbType_t *dbtype = (ACLDbType_t *)PERM_MALLOC(sizeof(ACLDbType_t));
+ ACLDbType_t *t2;
+ char *copy;
+ char *n2;
+ void *db;
+ int old1;
+ int old2;
+ int rv;
+
+ if (!dbtype) {
+ /* out of memory */
+ return -1;
+ }
+
+ if (auth_info) {
+ rv = ACL_DatabaseFind(errp, dbname, dbtype, (void **)&db);
+
+ if (rv != LAS_EVAL_TRUE) {
+ PERM_FREE(dbtype);
+ return -1;
+ }
+
+ /* Check the existing entry */
+ old1 = PListGetValue(auth_info, ACL_ATTR_DBTYPE_INDEX, (void **)&t2,
+ NULL);
+ old2 = PListGetValue(auth_info, ACL_ATTR_DATABASE_INDEX, (void **)&n2,
+ NULL);
+
+ if (old1 >= 0 && old2 >= 0) {
+ /* check if the old entry is same */
+ if (ACL_DbTypeIsEqual(errp, *dbtype, *t2)) {
+ /* Nothing to do */
+ PERM_FREE(dbtype);
+ return 0;
+ }
+ }
+ /* free the old entries */
+ if (old1 >= 0) {
+ PListDeleteProp(auth_info, ACL_ATTR_DBTYPE_INDEX, ACL_ATTR_DBTYPE);
+ PERM_FREE(t2);
+ }
+ if (old2 >= 0) {
+ PListDeleteProp(auth_info, ACL_ATTR_DATABASE_INDEX, ACL_ATTR_DATABASE);
+ PERM_FREE(n2);
+ }
+
+ /* Create new entries for "dbtype" & "dbname" */
+ copy = (char *)PERM_STRDUP(dbname);
+ if (!copy) return -1;
+ PListInitProp(auth_info, ACL_ATTR_DATABASE_INDEX,
+ ACL_ATTR_DATABASE, copy, 0);
+ PListInitProp(auth_info, ACL_ATTR_DBTYPE_INDEX, ACL_ATTR_DBTYPE,
+ dbtype, 0);
+ }
+ else {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* ACL_AuthInfoGetDbType
+ * INPUT
+ * auth_info A PList of the authentication name/value pairs as
+ * provided by EvalTestRights to the LAS.
+ * OUTPUT
+ * *t The DbType number. This can be the default dbtype
+ * number if the auth_info PList doesn't explicitly
+ * have a DbType entry.
+ * retcode 0 on success.
+ */
+NSAPI_PUBLIC int
+ACL_AuthInfoGetDbType(NSErr_t *errp, PList_t auth_info, ACLDbType_t *t)
+{
+ ACLDbType_t *dbtypep;
+
+ if (!auth_info ||
+ PListGetValue(auth_info, ACL_ATTR_DBTYPE_INDEX, (void **)&dbtypep, NULL) < 0)
+ {
+ /* No entry for "dbtype" */
+ *t = ACLDbTypeDefault;
+ } else {
+ *t = *dbtypep;
+ }
+
+ return 0;
+}
+
+/* ACL_AuthInfoGetDbname
+ * INPUT
+ * auth_info A PList of the authentication name/value pairs as
+ * provided by EvalTestRights to the LAS.
+ * OUTPUT
+ * dbname The database name. This can be the default database
+ * name if the auth_info PList doesn't explicitly
+ * have a database entry.
+ * retcode 0 on success.
+ */
+NSAPI_PUBLIC int
+ACL_AuthInfoGetDbname(PList_t auth_info, char **dbname)
+{
+ char *dbstr;
+
+ if (!auth_info ||
+ PListGetValue(auth_info, ACL_ATTR_DATABASE_INDEX, (void **)&dbstr, NULL) < 0)
+ {
+ /* No entry for "database" */
+ dbstr = ACLDatabaseDefault;
+ }
+
+ /* else the value was already set by the PListGetValue call */
+ *dbname = dbstr;
+ return 0;
+}
+
+NSAPI_PUBLIC DbParseFn_t
+ACL_DbTypeParseFn(NSErr_t *errp, const ACLDbType_t dbtype)
+{
+ if (ACL_DbTypeIsRegistered(errp, dbtype))
+ return ACLDbParseFnTable[(int)(PRSize)dbtype];
+ else
+ return 0;
+}
+
+/* The hash table is keyed by attribute name, and contains pointers to the
+ * PRCList headers. These in turn, circularly link a set of AttrGetter_s
+ * structures.
+ */
+NSAPI_PUBLIC int
+ACL_AttrGetterRegister(NSErr_t *errp, const char *attr, ACLAttrGetterFn_t fn,
+ ACLMethod_t m, ACLDbType_t d, int position, void *arg)
+{
+ ACLAttrGetter_t *getter;
+ PLHashEntry **hep;
+
+ if (position != ACL_AT_FRONT && position != ACL_AT_END) {
+ return -1;
+ }
+
+ ACL_CritEnter();
+
+ hep = PR_HashTableRawLookup(ACLAttrGetterHash, PR_HashCaseString(attr), attr);
+
+ /* Now, allocate the current entry */
+ getter = (ACLAttrGetter_t *)CALLOC(sizeof(ACLAttrGetter_t));
+ if (getter == NULL) {
+ ACL_CritExit();
+ return -1;
+ }
+ getter->method = m;
+ getter->dbtype = d;
+ getter->fn = fn;
+ getter->arg = arg;
+
+ if (*hep == 0) { /* New entry */
+
+ PR_INIT_CLIST(&getter->list);
+ PR_HashTableAdd(ACLAttrGetterHash, attr, (void *)getter);
+ }
+ else {
+
+ ACLAttrGetter_t *head = (ACLAttrGetter_t *)((*hep)->value);
+
+ PR_INSERT_BEFORE(&getter->list, &head->list);
+
+ if (position == ACL_AT_FRONT) {
+
+ /* Set new head of list */
+ (*hep)->value = (void *)getter;
+ }
+ }
+
+ ACL_CritExit();
+ return 0;
+}
+
+NSAPI_PUBLIC int
+ACL_AttrGetterFind(NSErr_t *errp, const char *attr,
+ ACLAttrGetterList_t *getters)
+{
+ *getters = PR_HashTableLookup(ACLAttrGetterHash, attr);
+ if (*getters)
+ return 0;
+ else
+ return -1;
+}
+
+NSAPI_PUBLIC
+ACLAttrGetter_t * ACL_AttrGetterFirst(ACLAttrGetterList_t *getters)
+{
+ ACLAttrGetter_t * first = 0;
+
+ if (getters && *getters) {
+
+ first = (ACLAttrGetter_t *)(*getters);
+ }
+
+ return first;
+}
+
+NSAPI_PUBLIC ACLAttrGetter_t *
+ACL_AttrGetterNext(ACLAttrGetterList_t *getters, ACLAttrGetter_t *last)
+{
+ ACLAttrGetter_t *head;
+ ACLAttrGetter_t *next = 0;
+
+ if (getters && *getters && last) {
+
+ head = (ACLAttrGetter_t *)(*getters);
+ if (head) {
+
+ /* End of list? */
+ if (last != (ACLAttrGetter_t *)PR_LIST_TAIL(&head->list)) {
+
+ /* No, get next entry */
+ next = (ACLAttrGetter_t *)PR_NEXT_LINK(&last->list);
+ }
+ }
+ }
+
+ return next;
+}
+
+int
+ACL_RegisterInit ()
+{
+ NSErr_t *errp = 0;
+ int rv;
+
+ /* Register the ldap database */
+ rv = ACL_DbTypeRegister(errp, ACL_DBTYPE_LDAP, parse_ldap_url, &ACL_DbTypeLdap);
+
+ return rv;
+}
+
diff --git a/lib/libaccess/register.h b/lib/libaccess/register.h
new file mode 100644
index 00000000..981e2cb8
--- /dev/null
+++ b/lib/libaccess/register.h
@@ -0,0 +1,98 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef ACL_REGISTER_HEADER
+#define ACL_REGISTER_HEADER
+
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include <libaccess/las.h>
+
+typedef void * ACLMethod_t;
+#define ACL_METHOD_ANY (ACLMethod_t)-1
+#define ACL_METHOD_INVALID (ACLMethod_t)-2
+typedef void * ACLDbType_t;
+#define ACL_DBTYPE_ANY (ACLDbType_t)-1
+#define ACL_DBTYPE_INVALID (ACLDbType_t)-2
+
+typedef struct ACLGetter_s {
+ ACLMethod_t method;
+ ACLDbType_t db;
+ AttrGetterFn fn;
+} ACLGetter_t;
+typedef ACLGetter_s * ACLGetter_p;
+
+/*
+ * Command values for the "position" argument to ACL_RegisterGetter
+ * Any positive >0 value is the specific position in the list to insert
+ * the new function.
+ */
+#define ACL_AT_FRONT 0
+#define ACL_AT_END -1
+#define ACL_REPLACE_ALL -2
+#define ACL_REPLACE_MATCHING -3
+
+#ifdef ACL_LIB_INTERNAL
+#define ACL_MAX_METHOD 32
+#define ACL_MAX_DBTYPE 32
+#endif
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC extern int
+ ACL_LasRegister( NSErr_t *errp, char *attr_name, LASEvalFunc_t
+ eval_func, LASFlushFunc_t flush_func );
+NSAPI_PUBLIC extern int
+ ACL_LasFindEval( NSErr_t *errp, char *attr_name, LASEvalFunc_t
+ *eval_funcp );
+NSAPI_PUBLIC extern int
+ ACL_LasFindFlush( NSErr_t *errp, char *attr_name, LASFlushFunc_t
+ *flush_funcp );
+extern void
+ ACL_LasHashInit( void );
+extern void
+ ACL_LasHashDestroy( void );
+
+/*
+ * Revised, normalized method/dbtype registration routines
+ */
+NSAPI_PUBLIC extern int
+ ACL_MethodRegister(const char *name, ACLMethod_t *t);
+NSAPI_PUBLIC extern int
+ ACL_MethodIsEqual(ACLMethod_t t1, ACLMethod_t t2);
+NSAPI_PUBLIC extern int
+ ACL_MethodNameIsEqual(ACLMethod_t t, const char *name);
+NSAPI_PUBLIC extern int
+ ACL_MethodFind(const char *name, ACLMethod_t *t);
+NSAPI_PUBLIC extern ACLMethod_t
+ ACL_MethodGetDefault();
+NSAPI_PUBLIC extern void
+ ACL_MethodSetDefault();
+NSAPI_PUBLIC extern int
+ ACL_AuthInfoGetMethod(PList_t auth_info, ACLMethod_t *t);
+
+NSAPI_PUBLIC extern int
+ ACL_DbTypeRegister(const char *name, DbParseFn_t func, ACLDbType_t *t);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeIsEqual(ACLDbType_t t1, ACLDbType_t t2);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeNameIsEqual(ACLDbType_t t, const char *name);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeFind(const char *name, ACLDbType_t *t);
+NSAPI_PUBLIC extern ACLDbType_t
+ ACL_DbTypeGetDefault();
+NSAPI_PUBLIC extern void
+ ACL_DbTypeSetDefault();
+NSAPI_PUBLIC extern int
+ ACL_AuthInfoGetDbType(PList_t auth_info, ACLDbType_t *t);
+
+NSAPI_PUBLIC extern int
+ ACL_RegisterGetter(AttrGetterFn fn, ACLMethod_t m, ACLDbType_t d, int
+ position, void *arg);
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/symbols.cpp b/lib/libaccess/symbols.cpp
new file mode 100644
index 00000000..ca1e18b1
--- /dev/null
+++ b/lib/libaccess/symbols.cpp
@@ -0,0 +1,350 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (symbols.c)
+ *
+ * This module implements a symbol table for ACL-related structures.
+ * The symbol table associates string names and types with pointers
+ * to various kinds of structures.
+ */
+/*
+#include <base/systems.h>
+*/
+#include <plhash.h>
+#include <base/util.h>
+#include <netsite.h>
+#define __PRIVATE_SYMBOLS
+#include "libaccess/symbols.h"
+#include <ctype.h>
+
+static PLHashEntry * symAllocEntry(void * pool, const void *unused);
+static void * symAllocTable(void * pool, PRSize size);
+static int symCmpName(const void * name1, const void * name2);
+static int symCmpValue(const void * value1, const void * value2);
+static PLHashNumber symHash(const void * symkey);
+static void symFreeEntry(void * pool, PLHashEntry * he, PRUintn flag);
+static void symFreeTable(void * pool, void * item);
+
+/* Table of pointers to functions associated with the hash table */
+static PLHashAllocOps SymAllocOps = {
+ symAllocTable, /* allocate the hash table */
+ symFreeTable, /* free the hash table */
+ symAllocEntry, /* allocate a table entry */
+ symFreeEntry, /* free a table entry */
+};
+
+static void * symAllocTable(void * pool, PRSize size)
+{
+ return (void *)PERM_MALLOC(size);
+}
+
+static void symFreeTable(void * pool, void * item)
+{
+ PERM_FREE(item);
+}
+
+
+
+static PLHashEntry * symAllocEntry(void * pool, const void *ignored)
+{
+ PLHashEntry * he;
+
+ he = (PLHashEntry *) PERM_MALLOC(sizeof(PLHashEntry));
+
+ return he;
+}
+
+static void symFreeEntry(void * pool, PLHashEntry * he, PRUintn flag)
+{
+ if (flag == HT_FREE_ENTRY) {
+ /* Just free the hash entry, not anything it references */
+ PERM_FREE(he);
+ }
+}
+
+
+static int symCmpName(const void * name1, const void * name2)
+{
+ Symbol_t * sym1 = (Symbol_t *)name1;
+ Symbol_t * sym2 = (Symbol_t *)name2;
+
+ return ((sym1->sym_type == sym2->sym_type) &&
+ !strcasecmp(sym1->sym_name, sym2->sym_name));
+}
+
+static int symCmpValue(const void * value1, const void * value2)
+{
+ return (value1 == value2);
+}
+
+static PLHashNumber symHash(const void * symkey)
+{
+ Symbol_t * sym = (Symbol_t *)symkey;
+ char * cp;
+ PLHashNumber h;
+
+ h = sym->sym_type;
+ cp = sym->sym_name;
+ if (cp) {
+ while (*cp) {
+ h = (h << 3) ^ tolower(*cp);
+ ++cp;
+ }
+ }
+
+ return h;
+}
+
+/* Helper function for symTableEnumerate() */
+typedef struct {
+ int (*func)(Symbol_t * sym, void * parg);
+ void * argp;
+} SymTableEnum_t;
+
+static int symTableEnumHelp(PLHashEntry * he, int n, void * step)
+{
+ SymTableEnum_t * ste = (SymTableEnum_t *)step;
+ int ret = 0;
+ int rv;
+
+ rv = (*ste->func)((Symbol_t *)(he->key), ste->argp);
+ if (rv != 0) {
+ if (rv & SYMENUMREMOVE) ret = HT_ENUMERATE_REMOVE;
+ if (rv & SYMENUMSTOP) ret |= HT_ENUMERATE_STOP;
+ }
+
+ return ret;
+}
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ * Description (symTableAddSym)
+ *
+ * This function adds a symbol definition to the symbol table.
+ * The symbol definition includes a name string, a type, and a
+ * reference to a structure.
+ *
+ * Arguments:
+ *
+ * table - handle for symbol table
+ * newsym - pointer to new symbol name and type
+ * symref - pointer to structure named by symbol
+ *
+ * Returns:
+ *
+ * If successful, the return code is zero. An error is indicated
+ * by a negative return code (SYMERRxxxx - see symbols.h).
+ */
+
+int symTableAddSym(void * table, Symbol_t * newsym, void * symref)
+{
+ SymTable_t * st = (SymTable_t *)table;
+ PLHashEntry * he;
+ PLHashEntry **hep;
+ PLHashNumber keyhash;
+ int rv = 0;
+
+ /* Compute the hash value for this symbol */
+ keyhash = symHash((const void *)newsym);
+
+ crit_enter(st->stb_crit);
+
+ /* See if another symbol already has the same name and type */
+ hep = PL_HashTableRawLookup(st->stb_ht, keyhash, (void *)newsym);
+ if (*hep == 0) {
+
+ /* Expand the hash table if necessary and allocate an entry */
+ he = PL_HashTableRawAdd(st->stb_ht,
+ hep, keyhash, (void *)newsym, symref);
+ }
+ else {
+ /* The symbol is already there. It's an error */
+ rv = SYMERRDUPSYM;
+ }
+
+ crit_exit(st->stb_crit);
+ return rv;
+}
+
+/*
+ * Description (symTableRemoveSym)
+ *
+ * This function removes an entry from a symbol table. It does
+ * not free the entry itself, just the hash entry that references
+ * it.
+ *
+ * Arguments:
+ *
+ * table - symbol table handle
+ * sym - pointer to symbol structure
+ */
+
+void symTableRemoveSym(void * table, Symbol_t * sym)
+{
+ SymTable_t * st = (SymTable_t *)table;
+
+ if (sym->sym_name != 0) {
+ crit_enter(st->stb_crit);
+ PL_HashTableRemove(st->stb_ht, (void *)sym);
+ crit_exit(st->stb_crit);
+ }
+}
+
+/*
+ * Description (symTableEnumerate)
+ *
+ * This function enumerates all of the entries in a symbol table,
+ * calling a specified function for each entry. The function
+ * specified by the caller may return flags indicating actions
+ * to be taken for each entry or whether to terminate the
+ * enumeration. These flags are defined in symbols.h as
+ * SYMENUMxxxx.
+ *
+ * Arguments:
+ *
+ * table - symbol table handle
+ * argp - argument for caller function
+ * func - function to be called for each entry
+ */
+
+void symTableEnumerate(void * table, void * argp,
+#ifdef UnixWare /* Fix bug in UnixWare compiler for name mangeling - nedh@sco.com */
+ ArgFn_symTableEnum func)
+#else
+ int (*func)(Symbol_t * sym, void * parg))
+#endif
+{
+ SymTable_t * st = (SymTable_t *)table;
+ SymTableEnum_t ste; /* enumeration arguments */
+
+ ste.func = func;
+ ste.argp = argp;
+
+ crit_enter(st->stb_crit);
+ (void)PL_HashTableEnumerateEntries(st->stb_ht,
+ symTableEnumHelp, (void *)&ste);
+ crit_exit(st->stb_crit);
+}
+
+/*
+ * Description (symTableFindSym)
+ *
+ * This function locates a symbol with a specified name and type
+ * in a given symbol table. It returns a pointer to the structure
+ * named by the symbol.
+ *
+ * Arguments:
+ *
+ * table - symbol table handle
+ * symname - symbol name string pointer
+ * symtype - symbol type code
+ * psymref - pointer to returned structure pointer
+ *
+ * Returns:
+ *
+ * If successful, the return code is zero and the structure pointer
+ * associated with the symbol name and type is returned in the
+ * location specified by 'psymref'. An error is indicated by a
+ * negative return code (SYMERRxxxx - see symbols.h).
+ */
+
+int symTableFindSym(void * table, char * symname,
+ int symtype, void **psymref)
+{
+ SymTable_t * st = (SymTable_t *)table;
+ Symbol_t sym;
+ void * symref;
+
+ /* Create temporary entry with fields needed by symHash() */
+ sym.sym_name = symname;
+ sym.sym_type = symtype;
+
+ crit_enter(st->stb_crit);
+
+ symref = PL_HashTableLookup(st->stb_ht, (void *)&sym);
+
+ crit_exit(st->stb_crit);
+
+ *psymref = symref;
+
+ return (symref) ? 0 : SYMERRNOSYM;
+}
+
+/*
+ * Description (symTableDestroy)
+ *
+ * This function destroys a symbol table created by symTableNew().
+ *
+ * Arguments:
+ *
+ * table - symbol table handle from symTableNew()
+ * flags - bit flags (unused - must be zero)
+ */
+
+void symTableDestroy(void * table, int flags)
+{
+ SymTable_t * st = (SymTable_t *)table;
+
+ if (st) {
+ if (st->stb_crit) {
+ crit_terminate(st->stb_crit);
+ }
+
+ if (st->stb_ht) {
+ PL_HashTableDestroy(st->stb_ht);
+ }
+
+ PERM_FREE(st);
+ }
+}
+
+/*
+ * Description (symTableNew)
+ *
+ * This function creates a new symbol table, and returns a handle
+ * for it.
+ *
+ * Arguments:
+ *
+ * ptable - pointer to returned symbol table handle
+ *
+ * Returns:
+ *
+ * If successful, the return code is zero and a handle for the new
+ * symbol table is returned in the location specified by 'ptable'.
+ * An error is indicated by a negative return code (SYMERRxxxx
+ * - see symbols.h).
+ */
+
+int symTableNew(void **ptable)
+{
+ SymTable_t * st;
+
+ /* Allocate the symbol table object */
+ st = (SymTable_t *)PERM_MALLOC(sizeof(SymTable_t));
+ if (st == 0) goto err_nomem;
+
+ /* Get a monitor for it */
+ st->stb_crit = crit_init();
+
+ st->stb_ht = PL_NewHashTable(0, symHash, symCmpName, symCmpValue,
+ &SymAllocOps, 0);
+ if (st->stb_ht == 0) goto err_nomem;
+
+ *ptable = st;
+ return 0;
+
+ err_nomem:
+ if (st) {
+ symTableDestroy(st, 0);
+ }
+ return SYMERRNOMEM;
+}
+
+NSPR_END_EXTERN_C
+
diff --git a/lib/libaccess/userauth.cpp b/lib/libaccess/userauth.cpp
new file mode 100644
index 00000000..3413fbd0
--- /dev/null
+++ b/lib/libaccess/userauth.cpp
@@ -0,0 +1,12 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* userauth.c
+ * This file contain code to authenticate user.
+ */
+
+
+
diff --git a/lib/libaccess/usi.cpp b/lib/libaccess/usi.cpp
new file mode 100644
index 00000000..677f3bd7
--- /dev/null
+++ b/lib/libaccess/usi.cpp
@@ -0,0 +1,371 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "assert.h"
+#include "libaccess/usi.h"
+
+/*
+ * Description (usiAlloc)
+ *
+ * This function is used to initialize a USIList_t structure to
+ * reference an array of unsigned integers, where the size of the
+ * array is specified. The caller is responsible for initializing
+ * the specified number of values in the array.
+ *
+ * Arguments:
+ *
+ * uilptr - pointer to list head
+ * count - number of entries to allocate
+ *
+ * Returns:
+ *
+ * If successful, a pointer to the USI_t array now referenced by the
+ * list head (uilptr) is returned. An error is indicated by a null
+ * return value.
+ */
+
+USI_t * usiAlloc(USIList_t * uilptr, int count)
+{
+ /* Is there space already allocated for this list? */
+ if (uilptr->uil_size > 0) {
+
+ /* If it's not big enough to hold the desired size, free it */
+ if (count > uilptr->uil_size) {
+ FREE(uilptr->uil_list);
+ UILINIT(uilptr);
+ }
+ }
+
+ /* Do we need space? */
+ if (uilptr->uil_size < count) {
+
+ /* Yes, allocate space for the specified number of values */
+ uilptr->uil_list = (USI_t *)MALLOC(sizeof(USI_t) * count);
+ if (uilptr->uil_list == 0) {
+
+ /* Error - no memory available */
+ uilptr->uil_count = 0;
+ return 0;
+ }
+
+ uilptr->uil_size = count;
+ }
+
+ uilptr->uil_count = count;
+
+ return uilptr->uil_list;
+}
+
+/*
+ * Description (usiInsert)
+ *
+ * This function is called to insert a specified USI_t value into
+ * a given list of USI_t values. The values are maintained in an
+ * array, where they are kept in ascending order. Duplicate values
+ * are rejected.
+ *
+ * Arguments:
+ *
+ * uilptr - pointer to list head
+ * usi - value to be inserted
+ *
+ * Returns:
+ *
+ * If the specified value is already in the list, zero is returned.
+ * If the value is successfully inserted into the list, +1 is
+ * returned. An error is indicated by a negative return value.
+ */
+
+int usiInsert(USIList_t * uilptr, USI_t usi)
+{
+ int ilow, ihigh, i;
+ USI_t * ids;
+
+ ids = uilptr->uil_list;
+
+ /* Binary search for specified group id */
+ i = 0;
+ for (ilow = 0, ihigh = uilptr->uil_count; ilow != ihigh; ) {
+
+ i = (ilow + ihigh) >> 1;
+ if (usi == ids[i]) {
+ /* The value is already in the list */
+ return 0;
+ }
+
+ if (usi > ids[i]) {
+ ilow = i + 1;
+ }
+ else {
+ ihigh = i;
+ }
+ }
+
+ /* Check for empty list */
+ if (uilptr->uil_count <= 0) {
+
+ /* Any space allocated for the list yet? */
+ if (uilptr->uil_size <= 0) {
+
+ /* No, allocate some initial space */
+ ids = (USI_t *) MALLOC(sizeof(USI_t) * 4);
+ if (ids == 0) {
+ /* Error - no memory available */
+ return -1;
+ }
+
+ uilptr->uil_size = 4;
+ uilptr->uil_list = ids;
+ }
+
+ /* Value will be inserted at ilow, which is zero */
+ }
+ else {
+
+ /*
+ * Set ilow to the index at which the specified value
+ * should be inserted.
+ */
+ if (usi > ids[i]) ++i;
+ ilow = i;
+
+ /* Is there space for another value? */
+ if (uilptr->uil_count >= uilptr->uil_size) {
+
+ /* No, expand the array to hold more values */
+ ids = (USI_t *)REALLOC(ids,
+ (uilptr->uil_size + 4) * sizeof(USI_t));
+ if (ids == 0) {
+ /* Error - no memory available */
+ return -1;
+ }
+
+ uilptr->uil_size += 4;
+ uilptr->uil_list = ids;
+ }
+
+ /* Copy higher values up */
+ for (i = uilptr->uil_count; i > ilow; --i) {
+ ids[i] = ids[i-1];
+ }
+ }
+
+ /* Add the new value */
+ ids[ilow] = usi;
+ uilptr->uil_count += 1;
+
+ return 1;
+}
+
+/*
+ * Description (usiPresent)
+ *
+ * This function is called to check whether a specified USI_t value
+ * is present in a given list.
+ *
+ * Arguments:
+ *
+ * uilptr - pointer to list head
+ * usi - value to check for
+ *
+ * Returns:
+ *
+ * The return value is the index of the value in the list, plus one,
+ * if the value is present in the list, 0 if it is not.
+ */
+
+int usiPresent(USIList_t * uilptr, USI_t usi)
+{
+ int ilow, ihigh, i;
+ USI_t * ids;
+
+ ids = uilptr->uil_list;
+
+ /* Binary search for specified group id */
+ i = 0;
+ for (ilow = 0, ihigh = uilptr->uil_count; ilow != ihigh; ) {
+
+ i = (ilow + ihigh) >> 1;
+ if (usi == ids[i]) {
+ /* The value is in the list */
+ return i + 1;
+ }
+
+ if (usi > ids[i]) {
+ ilow = i + 1;
+ }
+ else {
+ ihigh = i;
+ }
+ }
+
+ /* The value was not found */
+ return 0;
+}
+
+/*
+ * Description (usiRemove)
+ *
+ * This function is called to remove a specified USI_t value from
+ * a given list. The list is compressed when the value is removed.
+ *
+ * Arguments:
+ *
+ * uilptr - pointer to list head
+ * usi - value to be removed
+ *
+ * Returns:
+ *
+ * Returns the value returned by usiPresent(uilptr, usi).
+ */
+
+int usiRemove(USIList_t * uilptr, USI_t usi)
+{
+ USI_t * ids;
+ int i, j;
+
+ i = usiPresent(uilptr, usi);
+ if (i > 0) {
+
+ /* Compress the remaining values */
+ ids = uilptr->uil_list;
+ for (j = i ; j < uilptr->uil_count; ++j) {
+ ids[j-1] = ids[j];
+ }
+
+ /* Decrement the number of values and free space if none left */
+ if (--uilptr->uil_count <= 0) {
+ FREE(uilptr->uil_list);
+ UILINIT(uilptr);
+ }
+ }
+
+ return i;
+}
+
+/*
+ * Description (uilDuplicate)
+ *
+ * This function is called to make a duplicate of a specified
+ * source list, in a given destination list. Any existing list
+ * referenced by the destination list head is either overwritten
+ * or replaced with a newly allocated list. The values in the
+ * source list are copied to the destination. Note that the
+ * destination list area may be larger than the source list area
+ * on return, i.e. their uil_size values may differ.
+ *
+ * Arguments:
+ *
+ * dstptr - pointer to destination list head
+ * srcptr - pointer to source list head
+ *
+ * Returns:
+ *
+ * The number of elements in the source and destination lists is
+ * returned if successful. An error is indicated by a negative
+ * return value.
+ */
+
+int uilDuplicate(USIList_t * dstptr, USIList_t * srcptr)
+{
+ USI_t * idlist;
+ USI_t * srclist;
+ int count;
+ int i;
+
+ count = srcptr->uil_count;
+ srclist = srcptr->uil_list;
+
+ /* Allocate enough space in the destination list */
+ idlist = usiAlloc(dstptr, count);
+ if ((idlist == 0) && (count > 0)) {
+ /* Error - insufficient memory */
+ return -1;
+ }
+
+ /* Copy source values to destination */
+ for (i = 0; i < count; ++i) {
+ idlist[i] = srclist[i];
+ }
+
+ /* Return number of entries in destination list */
+ return count;
+}
+
+/*
+ * Description (uilMerge)
+ *
+ * This function is called to merge the values in a source list
+ * into a destination list. That is, any values in the source
+ * list which are not in the destination list will be inserted
+ * in it.
+ *
+ * Arguments:
+ *
+ * dstptr - pointer to destination list head
+ * srcptr - pointer to source list head
+ *
+ * Returns:
+ *
+ * The resulting number of elements in the destination list is
+ * returned if successful. An error is indicated by a negative
+ * return value.
+ */
+
+int uilMerge(USIList_t * dstptr, USIList_t * srcptr)
+{
+ USIList_t mglist; /* list head for merged list */
+ USI_t * srclist = srcptr->uil_list;
+ USI_t * dstlist = dstptr->uil_list;
+ int isrc, idst;
+ int scnt, dcnt;
+ int rv;
+
+ UILINIT(&mglist);
+
+ scnt = srcptr->uil_count;
+ dcnt = dstptr->uil_count;
+ isrc = 0;
+ idst = 0;
+
+ while ((isrc < scnt) && (idst < dcnt)) {
+
+ if (srclist[isrc] >= dstlist[idst]) {
+ rv = usiInsert(&mglist, dstlist[idst]);
+ if (rv < 0) goto punt;
+ if (srclist[isrc] == dstlist[idst]) ++isrc;
+ ++idst;
+ }
+ else if (srclist[isrc] < dstlist[idst]) {
+ rv = usiInsert(&mglist, srclist[isrc]);
+ if (rv < 0) goto punt;
+ ++isrc;
+ }
+ }
+
+ while (isrc < scnt) {
+ rv = usiInsert(&mglist, srclist[isrc]);
+ if (rv < 0) goto punt;
+ ++isrc;
+ }
+
+ while (idst < dcnt) {
+ rv = usiInsert(&mglist, dstlist[idst]);
+ if (rv < 0) goto punt;
+ ++idst;
+ }
+
+ UILREPLACE(dstptr, &mglist);
+
+ return dstptr->uil_count;
+
+ punt:
+ UILFREE(&mglist);
+ return rv;
+}
+
diff --git a/lib/libaccess/usrcache.cpp b/lib/libaccess/usrcache.cpp
new file mode 100644
index 00000000..2f79d2cc
--- /dev/null
+++ b/lib/libaccess/usrcache.cpp
@@ -0,0 +1,657 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* #define DBG_PRINT */
+
+
+#include <netsite.h>
+extern "C" {
+#include <secitem.h>
+}
+#include <base/crit.h>
+#include <ldaputil/errors.h>
+#include <libaccess/usrcache.h>
+#include <libaccess/las.h>
+#include <libaccess/authdb.h>
+#include "permhash.h"
+
+/* uid is unique within a database. The user cache tables are stored per
+ * database. The following table maps a database name to the corresponding
+ * user cache table. The user cache table is another hash table which stores
+ * the UserCacheObj instances.
+ */
+static PRHashTable *databaseUserCacheTable = 0;
+static time_t acl_usr_cache_lifetime = (time_t)120;
+static PRCList *usrobj_list = 0;
+static const int num_usrobj = 200;
+static CRITICAL usr_hash_crit = NULL; /* Controls user cache hash tables & */
+ /* usrobj link list */
+static pool_handle_t *usrcache_pool = NULL;
+static PRHashTable *singleDbTable = 0;
+
+#define USEROBJ_PTR(l) \
+ ((UserCacheObj*) ((char*) (l) - offsetof(UserCacheObj, list)))
+
+static void user_hash_crit_enter (void)
+{
+ /* Caching may be disabled (usr_hash_crit will be NULL) */
+ if (usr_hash_crit) crit_enter(usr_hash_crit);
+}
+
+static void user_hash_crit_exit (void)
+{
+ /* Caching may be disabled (usr_hash_crit will be NULL) */
+ if (usr_hash_crit) crit_exit(usr_hash_crit);
+}
+
+static void user_hash_crit_init (void)
+{
+ usr_hash_crit = crit_init();
+}
+
+static PRHashNumber
+usr_cache_hash_cert(const void *key)
+{
+ PRHashNumber h;
+ const unsigned char *s;
+ unsigned int i = 0;
+ SECItem *derCert = (SECItem *)key;
+ unsigned int len = derCert->len;
+
+ h = 0;
+ for (s = (const unsigned char *)derCert->data; i < len; s++, i++)
+ h = (h >> 28) ^ (h << 4) ^ *s;
+ return h;
+}
+
+static PRHashNumber
+usr_cache_hash_fn (const void *key)
+{
+ UserCacheObj *usrObj = (UserCacheObj *)key;
+
+ if (usrObj->derCert)
+ return usr_cache_hash_cert(usrObj->derCert);
+ else
+ return PR_HashCaseString(usrObj->uid);
+}
+
+static int
+usr_cache_compare_certs(const void *v1, const void *v2)
+{
+ const SECItem *c1 = (const SECItem *)v1;
+ const SECItem *c2 = (const SECItem *)v2;
+
+ return (c1->len == c2 ->len && !memcmp(c1->data, c2->data, c1->len));
+}
+
+static int
+usr_cache_compare_fn(const void *v1, const void *v2)
+{
+ UserCacheObj *usrObj1 = (UserCacheObj *)v1;
+ UserCacheObj *usrObj2 = (UserCacheObj *)v2;
+
+ if (usrObj1->derCert && usrObj2->derCert)
+ return usr_cache_compare_certs(usrObj1->derCert, usrObj2->derCert);
+ else if (!usrObj1->derCert && !usrObj2->derCert)
+ return PR_CompareCaseStrings(usrObj1->uid, usrObj1->uid);
+ else
+ return 0;
+}
+
+static PRHashTable *alloc_db2uid_table ()
+{
+ return PR_NewHashTable(0,
+ usr_cache_hash_fn,
+ usr_cache_compare_fn,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ usrcache_pool);
+}
+
+
+int acl_usr_cache_set_timeout (const int nsec)
+{
+ acl_usr_cache_lifetime = (time_t)nsec;
+ return 0;
+}
+
+
+int acl_usr_cache_enabled ()
+{
+ return (acl_usr_cache_lifetime > 0);
+}
+
+
+int acl_usr_cache_init ()
+{
+ UserCacheObj *usrobj;
+ int i;
+
+ if (acl_usr_cache_lifetime <= 0) {
+ /* Caching is disabled */
+ DBG_PRINT1("usrcache is disabled");
+ return 0;
+ }
+
+ usrcache_pool = pool_create();
+ user_hash_crit_init();
+
+ if (acl_num_databases() == 0) {
+ /* Something wrong -- No databases registered yet! */
+ return -1;
+ }
+ else if (acl_num_databases() == 1) {
+ /* Optimize for single database */
+ DBG_PRINT1("Optimizing usrcache for single db");
+ singleDbTable = alloc_db2uid_table();
+ }
+ else {
+ singleDbTable = 0;
+ databaseUserCacheTable = PR_NewHashTable(0,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ usrcache_pool);
+ }
+
+ /* Allocate first UserCacheObj and initialize the circular link list */
+ usrobj = (UserCacheObj *)pool_malloc(usrcache_pool, sizeof(UserCacheObj));
+ if (!usrobj) return -1;
+ memset((void *)usrobj, 0, sizeof(UserCacheObj));
+ usrobj_list = &usrobj->list;
+ PR_INIT_CLIST(usrobj_list);
+
+ /* Allocate rest of the UserCacheObj and put them in the link list */
+ for(i = 0; i < num_usrobj; i++){
+ usrobj = (UserCacheObj *)pool_malloc(usrcache_pool,
+ sizeof(UserCacheObj));
+
+ if (!usrobj) return -1;
+ memset((void *)usrobj, 0, sizeof(UserCacheObj));
+ PR_INSERT_AFTER(&usrobj->list, usrobj_list);
+ }
+
+ return (singleDbTable || databaseUserCacheTable) ? 0 : -1;
+}
+
+/* If the user hash table exists in the databaseUserCacheTable then return it.
+ * Otherwise, create a new hash table, insert it in the databaseUserCacheTable
+ * and then return it.
+ */
+static int usr_cache_table_get (const char *dbname, PRHashTable **usrTable)
+{
+ PRHashTable *table;
+
+ if (singleDbTable) {
+ *usrTable = singleDbTable;
+ return LAS_EVAL_TRUE;
+ }
+
+ user_hash_crit_enter();
+
+ table = (PRHashTable *)PR_HashTableLookup(databaseUserCacheTable,
+ dbname);
+
+ if (!table) {
+ /* create a new table and insert it in the databaseUserCacheTable */
+ table = alloc_db2uid_table();
+
+ if (table) {
+ PR_HashTableAdd(databaseUserCacheTable,
+ pool_strdup(usrcache_pool, dbname),
+ table);
+ }
+ }
+
+ *usrTable = table;
+
+ user_hash_crit_exit();
+
+ return table ? LAS_EVAL_TRUE : LAS_EVAL_FAIL;
+}
+
+int acl_usr_cache_insert (const char *uid, const char *dbname,
+ const char *userdn, const char *passwd,
+ const char *group,
+ const SECItem *derCert, const time_t time)
+{
+ PRHashTable *usrTable;
+ UserCacheObj *usrobj;
+ UserCacheObj key;
+ int rv;
+
+ if (acl_usr_cache_lifetime <= 0) {
+ /* Caching is disabled */
+ return LAS_EVAL_TRUE;
+ }
+
+ rv = usr_cache_table_get (dbname, &usrTable);
+
+ if (rv != LAS_EVAL_TRUE) return rv;
+
+ user_hash_crit_enter();
+
+ key.uid = (char *)uid;
+ key.derCert = (SECItem *)derCert;
+
+ usrobj = (UserCacheObj *)PR_HashTableLookup(usrTable, &key);
+
+ if (usrobj) {
+ time_t elapsed = time - usrobj->time;
+ int expired = (elapsed >= acl_usr_cache_lifetime);
+
+ /* Free & reset the old values in usrobj if -- there is an old value
+ * and if the new value is given then it is different or the usrobj
+ * has expired */
+ /* Set the field if the new value is given and the field is not set */
+ /* If the usrobj has not expired then we only want to update the field
+ * whose new value is non-NULL and different */
+
+ /* Work on the 'uid' field */
+ if (usrobj->uid &&
+ (uid ? strcmp(usrobj->uid, uid) : expired))
+ {
+ pool_free(usrcache_pool, usrobj->uid);
+ usrobj->uid = 0;
+ }
+ if (uid && !usrobj->uid) {
+ usrobj->uid = pool_strdup(usrcache_pool, uid);
+ }
+
+ /* Work on the 'userdn' field */
+ if (usrobj->userdn &&
+ (userdn ? strcmp(usrobj->userdn, userdn) : expired))
+ {
+ pool_free(usrcache_pool, usrobj->userdn);
+ usrobj->userdn = 0;
+ }
+ if (userdn && !usrobj->userdn) {
+ usrobj->userdn = pool_strdup(usrcache_pool, userdn);
+ }
+
+ /* Work on the 'passwd' field */
+ if (usrobj->passwd &&
+ (passwd ? strcmp(usrobj->passwd, passwd) : expired))
+ {
+ pool_free(usrcache_pool, usrobj->passwd);
+ usrobj->passwd = 0;
+ }
+ if (passwd && !usrobj->passwd) {
+ usrobj->passwd = pool_strdup(usrcache_pool, passwd);
+ }
+
+ /* Work on the 'group' field -- not replace a valid group */
+ if (!expired && usrobj->group &&
+ (group ? strcmp(usrobj->group, group) : expired))
+ {
+ pool_free(usrcache_pool, usrobj->group);
+ usrobj->group = 0;
+ }
+ if (group && !usrobj->group) {
+ usrobj->group = pool_strdup(usrcache_pool, group);
+ }
+
+ /* Work on the 'derCert' field */
+ if (usrobj->derCert &&
+ (derCert ? (derCert->len != usrobj->derCert->len ||
+ memcmp(usrobj->derCert->data, derCert->data,
+ derCert->len))
+ : expired))
+ {
+ SECITEM_FreeItem(usrobj->derCert, PR_TRUE);
+ usrobj->derCert = 0;
+ }
+ if (derCert && !usrobj->derCert) {
+ usrobj->derCert = SECITEM_DupItem((SECItem *)derCert);
+ }
+
+ /* Reset the time only if the usrobj has expired */
+ if (expired) {
+ DBG_PRINT1("Replace ");
+ usrobj->time = time;
+ }
+ else {
+ DBG_PRINT1("Update ");
+ }
+ }
+ else {
+ /* Get the last usrobj from the link list, erase it and use it */
+ /* Maybe the last usrobj is not invalid yet but we don't want to grow
+ * the list of usrobjs. The last obj is the best candidate for being
+ * not valid. We don't want to compare the time -- just use it.
+ */
+ PRCList *tail = PR_LIST_TAIL(usrobj_list);
+ usrobj = USEROBJ_PTR(tail);
+
+ /* If the removed usrobj is in the hashtable, remove it from there */
+ if (usrobj->hashtable) {
+ PR_HashTableRemove(usrobj->hashtable, usrobj);
+ }
+
+ /* Free the memory associated with the usrobj */
+ if (usrobj->userdn) pool_free(usrcache_pool, usrobj->userdn);
+ if (usrobj->passwd) pool_free(usrcache_pool, usrobj->passwd);
+ if (usrobj->group) pool_free(usrcache_pool, usrobj->group);
+ if (usrobj->derCert) SECITEM_FreeItem(usrobj->derCert, PR_TRUE);
+ if (usrobj->uid) pool_free(usrcache_pool, usrobj->uid);
+
+ /* Fill in the usrobj with the current data */
+ usrobj->uid = pool_strdup(usrcache_pool, uid);
+ usrobj->userdn = userdn ? pool_strdup(usrcache_pool, userdn) : 0;
+ usrobj->passwd = passwd ? pool_strdup(usrcache_pool, passwd) : 0;
+ usrobj->derCert = derCert ? SECITEM_DupItem((SECItem *)derCert) : 0;
+ usrobj->group = group ? pool_strdup(usrcache_pool, group) : 0;
+ usrobj->time = time;
+
+ /* Add the usrobj to the user hash table */
+ PR_HashTableAdd(usrTable, usrobj, usrobj);
+ usrobj->hashtable = usrTable;
+ DBG_PRINT1("Insert ");
+ }
+
+ /* Move the usrobj to the head of the list */
+ PR_REMOVE_LINK(&usrobj->list);
+ PR_INSERT_AFTER(&usrobj->list, usrobj_list);
+
+ /* Set the time in the UserCacheObj */
+ if (usrobj) {
+ rv = LAS_EVAL_TRUE;
+ }
+ else {
+ rv = LAS_EVAL_FAIL;
+ }
+
+ DBG_PRINT4("acl_usr_cache_insert: derCert = \"%s\" uid = \"%s\" at time = %ld\n",
+ usrobj->derCert ? (char *)usrobj->derCert->data : "<NONE>",
+ uid, time);
+
+ user_hash_crit_exit();
+ return rv;
+}
+
+static int acl_usr_cache_get_usrobj (const char *uid, const SECItem *derCert,
+ const char *dbname, const time_t time,
+ UserCacheObj **usrobj_out)
+{
+ PRHashTable *usrtable;
+ UserCacheObj *usrobj;
+ UserCacheObj key;
+ time_t elapsed;
+ int rv;
+
+ *usrobj_out = 0;
+
+ if (acl_usr_cache_lifetime <= 0) {
+ /* Caching is disabled */
+ return LAS_EVAL_FALSE;
+ }
+
+ rv = usr_cache_table_get(dbname, &usrtable);
+ if (!usrtable) return LAS_EVAL_FALSE;
+
+ key.uid = (char *)uid;
+ key.derCert = (SECItem *)derCert;
+
+ usrobj = (UserCacheObj *)PR_HashTableLookup(usrtable, &key);
+
+ if (!usrobj) return LAS_EVAL_FALSE;
+
+ rv = LAS_EVAL_FALSE;
+
+ elapsed = time - usrobj->time;
+
+ /* If the cache is valid, return the usrobj */
+ if (elapsed < acl_usr_cache_lifetime) {
+ rv = LAS_EVAL_TRUE;
+ *usrobj_out = usrobj;
+ DBG_PRINT4("usr_cache found: derCert = \"%s\" uid = \"%s\" at time = %ld\n",
+ usrobj->derCert ? (char *)usrobj->derCert->data : "<NONE>",
+ usrobj->uid, time);
+ }
+ else {
+ DBG_PRINT4("usr_cache expired: derCert = \"%s\" uid = \"%s\" at time = %ld\n",
+ usrobj->derCert ? (char *)usrobj->derCert->data : "<NONE>",
+ usrobj->uid, time);
+ }
+
+ return rv;
+}
+
+int acl_usr_cache_passwd_check (const char *uid, const char *dbname,
+ const char *passwd,
+ const time_t time, char **dn,
+ pool_handle_t *pool)
+{
+ UserCacheObj *usrobj;
+ int rv;
+
+ user_hash_crit_enter();
+ rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE && usrobj->passwd && passwd &&
+ !strcmp(usrobj->passwd, passwd))
+ {
+ /* extract dn from the usrobj */
+ *dn = usrobj->userdn ? pool_strdup(pool, usrobj->userdn) : 0;
+ rv = LAS_EVAL_TRUE;
+ DBG_PRINT1("Success ");
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ DBG_PRINT1("Failed ");
+ }
+
+ DBG_PRINT3("acl_usr_cache_passwd_check: uid = \"%s\" at time = %ld\n",
+ uid, time);
+ user_hash_crit_exit();
+
+ return rv;
+}
+
+
+static int group_check_helper (UserCacheObj *usrobj, void *val)
+{
+ if (usrobj->group && !strcmp(usrobj->group, (char *)val))
+ return LAS_EVAL_TRUE;
+ else
+ return LAS_EVAL_FALSE;
+}
+
+int acl_usr_cache_group_check (const char *uid, const char *dbname,
+ const char *group, const time_t time)
+{
+ UserCacheObj *usrobj;
+ int rv;
+
+ user_hash_crit_enter();
+ rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE && usrobj->group && group &&
+ !strcmp(usrobj->group, group))
+ {
+ DBG_PRINT1("Success ");
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ DBG_PRINT1("Failed ");
+ }
+
+ DBG_PRINT3("acl_usr_cache_group_check: uid = \"%s\" group = \"%s\"\n",
+ uid, group ? group : "<NONE>");
+ user_hash_crit_exit();
+
+ return rv;
+}
+
+int acl_usr_cache_group_len_check (const char *uid, const char *dbname,
+ const char *group, const int len,
+ const time_t time)
+{
+ UserCacheObj *usrobj;
+ int rv;
+
+ user_hash_crit_enter();
+ rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE && usrobj->group && group &&
+ !strncmp(usrobj->group, group, len))
+ {
+ rv = LAS_EVAL_TRUE;
+ DBG_PRINT1("Success ");
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ DBG_PRINT1("Failed ");
+ }
+
+ DBG_PRINT3("acl_usr_cache_group_check: uid = \"%s\" group = \"%s\"\n",
+ uid, group);
+ user_hash_crit_exit();
+
+ return rv;
+}
+
+
+int acl_usr_cache_get_userdn (const char *uid, const char *dbname,
+ const time_t time, char **userdn,
+ pool_handle_t *pool)
+{
+ UserCacheObj *usrobj;
+ int rv;
+
+ *userdn = 0;
+ user_hash_crit_enter();
+ rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE) {
+ *userdn = usrobj->userdn ? pool_strdup(pool, usrobj->userdn) : 0;
+ DBG_PRINT1("Success ");
+ }
+ else {
+ DBG_PRINT1("Failed ");
+ }
+
+ DBG_PRINT3("acl_usr_cache_get_userdn: uid = \"%s\" userdn = \"%s\"\n",
+ uid, *userdn ? *userdn : "<NONE>");
+ user_hash_crit_exit();
+
+ return *userdn ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+}
+
+int acl_usr_cache_userdn_check (const char *uid, const char *dbname,
+ const char *userdn, const time_t time)
+{
+ UserCacheObj *usrobj;
+ int rv;
+
+ user_hash_crit_enter();
+ rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE && usrobj->userdn && userdn &&
+ !strcmp(usrobj->userdn, userdn))
+ {
+ DBG_PRINT1("Success ");
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ DBG_PRINT1("Failed ");
+ }
+
+ DBG_PRINT3("acl_usr_cache_userdn_check: uid = \"%s\" userdn = \"%s\"\n",
+ uid, userdn ? userdn : "<NONE>");
+ user_hash_crit_exit();
+
+ return rv;
+}
+
+int acl_usr_cache_set_userdn (const char *uid, const char *dbname,
+ const char *userdn, const time_t time)
+{
+ int rv;
+
+ /* acl_usr_cache_insert updates the existing un-expired entry or creates a
+ * new one */
+ rv = acl_usr_cache_insert(uid, dbname, userdn, 0, 0, 0, time);
+
+ return rv;
+}
+
+int acl_usr_cache_get_group (const char *uid, const char *dbname,
+ const time_t time, char **group,
+ pool_handle_t *pool)
+{
+ UserCacheObj *usrobj;
+ int rv;
+
+ *group = 0;
+ user_hash_crit_enter();
+ rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE) {
+ *group = usrobj->group ? pool_strdup(pool, usrobj->group) : 0;
+ DBG_PRINT1("Success ");
+ }
+ else {
+ DBG_PRINT1("Failed ");
+ }
+
+ DBG_PRINT3("acl_usr_cache_get_group: uid = \"%s\" group = \"%s\"\n",
+ uid, *group ? *group : "<NONE>");
+ user_hash_crit_exit();
+
+ return *group ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+}
+
+int acl_usr_cache_set_group (const char *uid, const char *dbname,
+ const char *group, const time_t time)
+{
+ int rv;
+
+ /* acl_usr_cache_insert updates the existing un-expired entry or creates a
+ * new one */
+ rv = acl_usr_cache_insert(uid, dbname, 0, 0, group, 0, time);
+
+ return rv;
+}
+
+int acl_cert_cache_insert (void *cert_in, const char *dbname,
+ const char *uid, const char *dn,
+ const time_t time)
+{
+ CERTCertificate *cert = (CERTCertificate *)cert_in;
+ SECItem derCert = cert->derCert;
+ int rv;
+
+ rv = acl_usr_cache_insert(uid, dbname, dn, 0, 0, &derCert, time);
+
+ return rv;
+}
+
+/* Returns LAS_EVAL_TRUE if the user's cache is valid and returns uid */
+int acl_cert_cache_get_uid (void *cert_in, const char *dbname,
+ const time_t time, char **uid, char **dn,
+ pool_handle_t *pool)
+{
+ CERTCertificate *cert = (CERTCertificate *)cert_in;
+ SECItem derCert = cert->derCert;
+ UserCacheObj *usrobj = 0;
+ int rv;
+
+ rv = acl_usr_cache_get_usrobj(0, &derCert, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE && usrobj && usrobj->uid) {
+ *uid = pool_strdup(pool, usrobj->uid);
+ *dn = usrobj->userdn ? pool_strdup(pool, usrobj->userdn) : 0;
+ }
+ else {
+ *uid = 0;
+ *dn = 0;
+ rv = LAS_EVAL_FALSE;
+ }
+
+ return rv;
+}
+
diff --git a/lib/libaccess/utest.mk b/lib/libaccess/utest.mk
new file mode 100644
index 00000000..f33e6e6d
--- /dev/null
+++ b/lib/libaccess/utest.mk
@@ -0,0 +1,61 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+#CFLAGS = -g -DDEBUG -I.
+CFLAGS = -g -I. -I../../../include $(TESTFLAGS)
+#LEX = flex
+CC=gcc
+
+HEAD = aclparse.h acltools.h lparse.h acl.h acleval.h lasdns.h lasip.h mthash.h stubs.h aclscan.h acl.tab.h
+XSRC = aclparse.y aclscan.l
+CSRC = acleval.c aclutil.c lasdns.c lasip.c lastod.c mthash.c testmain.c acltools.c space.c acl.tab.c acl.yy.c
+SRC = $(HEAD) $(XSRC) $(CSRC)
+
+XOBJ = acl.tab.o acl.yy.o testmain.o acltools.o
+COBJ = $(CSRC:%.c=%.o)
+OBJ = $(XOBJ) $(COBJ)
+
+always: $(OBJ)
+
+acleval.o: stubs.h aclparse.h acl.h acleval.h mthash.h
+
+aclutil.o: acl.h aclparse.h
+
+lasdns.o: acl.h aclparse.h lasdns.h mthash.h
+
+lasip.o: acl.h aclparse.h lasip.h
+
+lastod.o: acl.h aclparse.h
+
+acltools.o: aclparse.h aclscan.h lparse.h aclparse.y
+
+testmain.o: aclparse.h acltools.h
+
+acl.yy.o: acl.yy.c acl.tab.h
+
+acl.yy.o acl.tab.o acltools.o: aclparse.h acltools.h lparse.h
+
+yacc: aclparse.y
+ $(YACC) -dv aclparse.y
+ mv y.tab.h acl.tab.h
+ mv y.tab.c acl.tab.c
+#sed -f yy-sed y.tab.h > acl.tab.h
+#sed -f yy-sed y.tab.c > acl.tab.c
+
+# Should only run this on an SGI, where flex() is present
+flex: aclscan.l
+ $(LEX) aclscan.l
+ mv lex.yy.c acl.yy.c
+#sed -f yy-sed lex.yy.c > acl.yy.c
+
+clean:
+ rm -f aclparse aclparse.pure y.output acl.tab.c acl.tab.h acl.yy.c lex.yy.c y.tab.c y.tab.h aclparse.c $(OBJ)
+
+# Check it out from the RCS directory
+$(SRC): RCS/$$@,v
+ co $@
diff --git a/lib/libaccess/utest/.purify b/lib/libaccess/utest/.purify
new file mode 100644
index 00000000..56b9983e
--- /dev/null
+++ b/lib/libaccess/utest/.purify
@@ -0,0 +1,19 @@
+suppress umr process_gethost
+suppress umr _door_gethostbyname_r
+suppress umr _get_hostserv_inetnetdir_byname
+suppress umr _get_hostserv_inetnetdir_byaddr
+suppress umr gethostbyname_r
+suppress umr _nsc_trydoorcall
+suppress umr LASDnsBuild
+suppress umr PR_HashString
+suppress umr mthsearch
+suppress umr Hash
+suppress umr strcmp
+suppress umr mthsearch
+suppress umr strlen
+suppress umr strdup
+suppress umr strcpy
+suppress umr PListFindValue
+suppress umr LASIpEval
+suppress umr LASDnsEval
+suppress mlk system_strdup_perm
diff --git a/lib/libaccess/utest/Makefile b/lib/libaccess/utest/Makefile
new file mode 100644
index 00000000..2acedff0
--- /dev/null
+++ b/lib/libaccess/utest/Makefile
@@ -0,0 +1,119 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+#
+MCOM_ROOT=../../../..
+MODULE=LibAcl
+include ../../../nsdefs.mk
+
+OBJDEST=.
+UTESTDEST=utest
+
+include ../../../nsconfig.mk
+
+MODULE_CFLAGS=-I$(NSROOT)/include/libaccess -I$(NSROOT)/include -I$(NSROOT)/include/public -I. -DACL_LIB_INTERNAL
+
+include $(INCLUDE_DEPENDS)
+
+#TESTFLAGS = -DUTEST -DDEBUG_LEVEL_2
+TESTFLAGS = -DUTEST
+CC = $(CCC)
+
+CSRC = acltest.cpp onetest.cpp ustubs.cpp twotest.cpp
+TSRC = aclfile0 aclfile1 aclfile2 aclfile3 aclfile4 aclfile5 aclfile6 aclfile7 aclfile8 aclfile9 aclfile10 aclfile11 aclfile12 aclfile13 aclfile14 aclfile15 aclfile16 aclfile17 aclfile18 aclfile19 test.ref
+SRC = $(CSRC) $(TSRC)
+XSRC = \
+ ../oneeval.cpp \
+ ../lastod.cpp \
+ ../lasip.cpp \
+ ../aclutil.cpp \
+ ../lasdns.cpp \
+ ../acl.tab.cpp \
+ ../acl.yy.cpp \
+ ../acltools.cpp \
+ ../aclspace.cpp \
+ ../lasgroup.cpp \
+ ../lasuser.cpp \
+ ../lasprogram.cpp \
+ ../nseframe.cpp \
+ ../aclcache.cpp \
+ ../register.cpp \
+ ../symbols.cpp \
+ ../method.cpp \
+ ../authdb.cpp
+
+COBJ = $(CSRC:%.cpp=%.o)
+XOBJ = $(XSRC:../%.cpp=%.o)
+
+# This may be needed for other platforms too
+ifeq ($(ARCH), IRIX)
+XLIBS = -rpath $(LDAP_LIBPATH)
+endif
+
+ifeq ($(ARCH), HPUX)
+XLIBS = -lpthread
+endif
+ifeq ($(ARCH), SOLARIS)
+XLIBS = -lsocket -lnsl -ldl -lposix4
+endif
+
+XLIBS+= $(OBJDIR)/lib/base/plist.o \
+ $(OBJDIR)/lib/base/pool.o \
+ $(OBJDIR)/lib/base/util.o \
+ $(OBJDIR)/lib/base/ereport.o \
+ $(OBJDIR)/lib/base/system.o \
+ $(OBJDIR)/lib/base/shexp.o \
+ $(OBJDIR)/lib/base/pblock.o \
+ $(OBJDIR)/lib/base/file.o \
+ $(OBJDIR)/lib/base/systhr.o \
+ $(OBJDIR)/lib/base/nscperror.o \
+ $(OBJDIR)/lib/libldapu.a \
+ $(LIBNSPR)
+
+all: $(COBJ) $(TSRC) acltest
+ ./acltest > test.out
+ diff test.ref test.out
+ @echo
+ @echo "The unit test is passed if there is no diff output, and the"
+ @echo "Purify window shows no errors and 0 bytes leaked."
+ @echo
+ @echo "Run - gmake coverage - manually to get code coverage analysis."
+ @echo
+
+aclparse: ustubs.o testmain.o $(XOBJ)
+ purify $(CC) -o aclparse testmain.o $(XOBJ) ustubs.o $(XLIBS)
+
+aclparse.pure: acl.tab.o acl.yy.o testmain.o acltools.o ustubs.o
+ purify -user-path=.. $(CC) -o aclparse.pure $(XOBJ) ustubs.o $(XLIBS)
+
+onetest: onetest.o ustubs.o $(XOBJ)
+ $(CC) -o onetest onetest.o $(XOBJ) ustubs.o $(XLIBS)
+
+twotest: twotest.o ustubs.o $(XOBJ)
+ $(CC) -o twotest twotest.o $(XOBJ) ustubs.o $(XLIBS)
+
+acltest: acltest.o ustubs.o $(XOBJ)
+# purify $(CC) -o acltest acltest.o $(XOBJ) ustubs.o $(XLIBS)
+ $(CC) -o acltest acltest.o $(XOBJ) ustubs.o $(XLIBS)
+
+coverage: acltest.o ustubs.o $(XOBJ)
+ purecov $(CC) -o acltestcov acltest.o $(XOBJ) ustubs.o $(XLIBS)
+ rm -f *.pcv
+ acltestcov
+
+lasemail: lasemail.o
+ $(LD) -G -h lasemail.so -o lasemail.so lasemail.o
+
+#$(XOBJ): $(XSRC)
+# cd ..; gmake OBJDEST=$(UTESTDEST) CC=$(OCC) TESTFLAGS=$(TESTFLAGS)
+
+%.o:../%.c
+ $(CC) -c $(CFLAGS) $(TESTFLAGS) $(MCC_INCLUDE) -I.. $< -o $(OBJDEST)/$*.o
+
+%.o:../%.cpp
+ $(CC) -c $(CFLAGS) $(TESTFLAGS) $(MCC_INCLUDE) -I.. $< -o $(OBJDEST)/$*.o
diff --git a/lib/libaccess/utest/acl.dat b/lib/libaccess/utest/acl.dat
new file mode 100644
index 00000000..d640adca
--- /dev/null
+++ b/lib/libaccess/utest/acl.dat
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+
+acl davids;
+
+deny (all) dns=aruba.mcom.com;
diff --git a/lib/libaccess/utest/aclfile0 b/lib/libaccess/utest/aclfile0
new file mode 100644
index 00000000..8bb2a428
--- /dev/null
+++ b/lib/libaccess/utest/aclfile0
@@ -0,0 +1,55 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile0;
+deny with uri="test";
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+
+acl aclfile0.0;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.1;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.2;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.3;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.4;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.5;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.6;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.7;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.8;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.9;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.10;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.11;
+allow (read, write, execute) (timeofday<2100);
+acl aclfile0.12;
+authenticate (user, group) {
+ database=franco;
+ method=basic;
+};
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
diff --git a/lib/libaccess/utest/aclfile1 b/lib/libaccess/utest/aclfile1
new file mode 100644
index 00000000..e148f1a1
--- /dev/null
+++ b/lib/libaccess/utest/aclfile1
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile1;
+deny (read, write, execute) (timeofday<2100);
+deny (read, write, execute) (dayofweek!=sun);
diff --git a/lib/libaccess/utest/aclfile10 b/lib/libaccess/utest/aclfile10
new file mode 100644
index 00000000..f0f5a223
--- /dev/null
+++ b/lib/libaccess/utest/aclfile10
@@ -0,0 +1,13 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile10;
+deny absolute (read) ip="17.34.*";
+allow (read,write) timeofday>1700;
+deny (read) dns="*.mcom.com";
+allow (read,write) dayofweek=mon;
diff --git a/lib/libaccess/utest/aclfile11 b/lib/libaccess/utest/aclfile11
new file mode 100644
index 00000000..9fe73cb2
--- /dev/null
+++ b/lib/libaccess/utest/aclfile11
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile11;
+allow (read) (timeofday<2100);
+allow (html_write, execute) (dayofweek!=sun);
diff --git a/lib/libaccess/utest/aclfile12 b/lib/libaccess/utest/aclfile12
new file mode 100644
index 00000000..ac154d7a
--- /dev/null
+++ b/lib/libaccess/utest/aclfile12
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile12;
+allow (read) (timeofday<2100);
+allow (read, html_write, execute) (dayofweek!=sun);
diff --git a/lib/libaccess/utest/aclfile13 b/lib/libaccess/utest/aclfile13
new file mode 100644
index 00000000..7334d03d
--- /dev/null
+++ b/lib/libaccess/utest/aclfile13
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile13;
+allow (read) (ip="17.34.1.1+255.255.0.0");
+allow (html_write) (dns!="*.microsoft.com");
diff --git a/lib/libaccess/utest/aclfile14 b/lib/libaccess/utest/aclfile14
new file mode 100644
index 00000000..5fc5c706
--- /dev/null
+++ b/lib/libaccess/utest/aclfile14
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile14;
+allow (read, write) (ip="17.34.*");
+deny (write) (dns!="*.mcom.com");
diff --git a/lib/libaccess/utest/aclfile15 b/lib/libaccess/utest/aclfile15
new file mode 100644
index 00000000..2d8701ec
--- /dev/null
+++ b/lib/libaccess/utest/aclfile15
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile15;
+allow (html_read, write) (dns="*.mcom.com");
+deny (read) (ip="17.34.*");
diff --git a/lib/libaccess/utest/aclfile16 b/lib/libaccess/utest/aclfile16
new file mode 100644
index 00000000..54ce99f8
--- /dev/null
+++ b/lib/libaccess/utest/aclfile16
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile16;
+allow (html_read, write) (dns="*.mcom.com");
+deny (read) (ip="17.34.1.1 + 255.255.0.0");
diff --git a/lib/libaccess/utest/aclfile17 b/lib/libaccess/utest/aclfile17
new file mode 100644
index 00000000..128076f3
--- /dev/null
+++ b/lib/libaccess/utest/aclfile17
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile17;
+allow absolute (all) (dns="*.mcom.com");
+deny (read) (ip="17.34.1.1+255.255.0.0");
diff --git a/lib/libaccess/utest/aclfile18 b/lib/libaccess/utest/aclfile18
new file mode 100644
index 00000000..4a80bc27
--- /dev/null
+++ b/lib/libaccess/utest/aclfile18
@@ -0,0 +1,19 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile18;
+authenticate (user) {
+ method=SSL;
+ database=LDAP;
+};
+allow (read, write, execute, create) dns="*.mcom.com";
+authenticate (user) {
+ method=basic;
+ database=20;
+};
+allow (read, write, execute, create) (timeofday>1700 or timeofday<0800);
diff --git a/lib/libaccess/utest/aclfile19 b/lib/libaccess/utest/aclfile19
new file mode 100644
index 00000000..4433f4c7
--- /dev/null
+++ b/lib/libaccess/utest/aclfile19
@@ -0,0 +1,14 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile19A;
+deny (read, write, execute, create) dns!="*.mcom.com";
+allow absolute (read) ((timeofday>1700 or timeofday<0800) or dayofweek=satsunmon);
+
+acl aclfile19B;
+deny (write) dns="*.mcom.com";
diff --git a/lib/libaccess/utest/aclfile2 b/lib/libaccess/utest/aclfile2
new file mode 100644
index 00000000..eee5c30c
--- /dev/null
+++ b/lib/libaccess/utest/aclfile2
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile2;
+deny (read) (timeofday<2100);
+deny (read) (dayofweek!=sun);
diff --git a/lib/libaccess/utest/aclfile3 b/lib/libaccess/utest/aclfile3
new file mode 100644
index 00000000..094c1abe
--- /dev/null
+++ b/lib/libaccess/utest/aclfile3
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile3;
+allow (read) (timeofday<2100);
+allow (read) (dayofweek!=sun);
diff --git a/lib/libaccess/utest/aclfile4 b/lib/libaccess/utest/aclfile4
new file mode 100644
index 00000000..befc7b4b
--- /dev/null
+++ b/lib/libaccess/utest/aclfile4
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile4;
+allow (read) (timeofday>0700);
+allow (write) (dayofweek!=sun);
diff --git a/lib/libaccess/utest/aclfile5 b/lib/libaccess/utest/aclfile5
new file mode 100644
index 00000000..8b0e1e8d
--- /dev/null
+++ b/lib/libaccess/utest/aclfile5
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile5;
+allow (read) (ip="17.34.*");
+allow (write) (dns!="*.microsoft.com");
diff --git a/lib/libaccess/utest/aclfile6 b/lib/libaccess/utest/aclfile6
new file mode 100644
index 00000000..9646b548
--- /dev/null
+++ b/lib/libaccess/utest/aclfile6
@@ -0,0 +1,23 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile6;
+allow (read,
+write) (ip="17.34.*");
+allow (read, write) (ip="17.34.*");
+allow (read, write) (ip="17.34.*");
+allow (read, write) (ip="17.34.*");
+allow (read, write) (ip="17.34.*");
+allow (read, write) (ip="17.34.*");
+deny (write)
+(dns!="*.mcom.com");
+deny (write) (dns!="*.mcom.com");
+deny (write) (dns!="*.mcom.com");
+deny (write) (dns!="*.mcom.com");
+deny (write) (dns!="*.mcom.com");
+deny (write) (dns!="*.mcom.com");
diff --git a/lib/libaccess/utest/aclfile7 b/lib/libaccess/utest/aclfile7
new file mode 100644
index 00000000..d8f9aa13
--- /dev/null
+++ b/lib/libaccess/utest/aclfile7
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile7;
+allow (read,write) (dns="*.mcom.com");
+deny (read) (ip="17.34.*");
diff --git a/lib/libaccess/utest/aclfile8 b/lib/libaccess/utest/aclfile8
new file mode 100644
index 00000000..b11cfe7e
--- /dev/null
+++ b/lib/libaccess/utest/aclfile8
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile8;
+allow (read, write, execute, create) dns="*.mcom.com";
+allow (read, write, execute, create) (timeofday>1700 or timeofday<0800);
diff --git a/lib/libaccess/utest/aclfile9 b/lib/libaccess/utest/aclfile9
new file mode 100644
index 00000000..2a0ab35e
--- /dev/null
+++ b/lib/libaccess/utest/aclfile9
@@ -0,0 +1,11 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile9;
+deny (read) ip="*.34.*+*.128.*.0";
+allow (read, write, execute, create) ((timeofday>1700 or timeofday<0800) or dayofweek=satsunmon);
diff --git a/lib/libaccess/utest/aclgrp0 b/lib/libaccess/utest/aclgrp0
new file mode 100644
index 00000000..ba08fbf1
--- /dev/null
+++ b/lib/libaccess/utest/aclgrp0
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclgrp0;
+allow (read, write, execute) (group = marketing or group!="Directory Administrators");
diff --git a/lib/libaccess/utest/aclgrp1 b/lib/libaccess/utest/aclgrp1
new file mode 100644
index 00000000..7a804404
--- /dev/null
+++ b/lib/libaccess/utest/aclgrp1
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclgrp1;
+allow (read, write, execute) (group!="Directory Administrators");
diff --git a/lib/libaccess/utest/aclgrp2 b/lib/libaccess/utest/aclgrp2
new file mode 100644
index 00000000..13938c19
--- /dev/null
+++ b/lib/libaccess/utest/aclgrp2
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclgrp2;
+allow (read, write, execute) (group=marketing);
diff --git a/lib/libaccess/utest/aclgrp3 b/lib/libaccess/utest/aclgrp3
new file mode 100644
index 00000000..30b44d5c
--- /dev/null
+++ b/lib/libaccess/utest/aclgrp3
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclgrp3;
+allow (read, write, execute) (group>"Directory Admin,marketing");
diff --git a/lib/libaccess/utest/aclgrp4 b/lib/libaccess/utest/aclgrp4
new file mode 100644
index 00000000..5b07d6c2
--- /dev/null
+++ b/lib/libaccess/utest/aclgrp4
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclgrp4;
+allow (read, write, execute) (group = " marketing ,, Directory Administrators ,, ");
diff --git a/lib/libaccess/utest/acltest.cpp b/lib/libaccess/utest/acltest.cpp
new file mode 100644
index 00000000..c643f873
--- /dev/null
+++ b/lib/libaccess/utest/acltest.cpp
@@ -0,0 +1,796 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <stdio.h>
+#include <netsite.h>
+#include <base/session.h>
+#include <base/daemon.h>
+#include <base/systhr.h>
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include "../aclpriv.h"
+#include <libaccess/aclproto.h>
+#include "../aclcache.h"
+#include <libaccess/las.h>
+
+
+extern ACLListHandle_t *ACL_ParseFile(NSErr_t *errp, char *filename);
+
+int
+TestEvalFunc(NSErr_t *errp, char *attr, CmpOp_t comparator,
+ char *attr_pattern, ACLCachable_t *cachable,
+ void **las_cookie, PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth)
+{
+ return 0;
+}
+
+void
+TestFlushFunc(void **cookie)
+{
+ return;
+}
+
+static int parse_dburl (NSErr_t *errp, ACLDbType_t dbtype,
+ const char *dbname, const char *url,
+ PList_t plist, void **db)
+{
+ *db = strdup(url);
+ return 0;
+}
+
+
+main()
+{
+ ACLListHandle_t *acl_list;
+ int result;
+ ACLCachable_t cachable = 0;
+ void *las_cookie=NULL;
+ ACLEvalHandle_t eval;
+ char *rights[3];
+ char filename[20];
+ char newfilename[25];
+ int i;
+ char *map_generic[7];
+ LASEvalFunc_t Eval_funcp;
+ LASFlushFunc_t Flush_funcp;
+ char *bong;
+ char *bong_type;
+ char *acl_tag;
+ int expr_num;
+ int ii;
+ char **name_list;
+ ACLMethod_t method=NULL;
+ ACLDbType_t dbtype=NULL;
+ int rv;
+ ACLAttrGetterList_t aglist;
+ ACLAttrGetter_t *agptr;
+ char **names;
+ int cnt;
+
+ systhread_init("acl_utest");
+
+ char *acl_file_list[3] = {"aclfile6", "aclfile7", NULL};
+ char *new_filename = "merge6_7";
+ char *acl_name_list[3] = {"aclfile6", "aclfile7", NULL};
+ char *new_aclname = "merge6_7";
+ char *bad_acl_file_list[3] = {"bad_aclfile6", "bad_aclfile7", NULL};
+
+ if ( ACL_FileMergeFile(NULL, new_filename, bad_acl_file_list, 0) < 0 ) {
+ printf("Failed ACL_FileMergeFile() test.\n");
+ }
+
+ if ( ACL_FileMergeFile(NULL, new_filename, acl_file_list, 0) < 0 ) {
+ printf("Failed ACL_FileMergeFile() test.\n");
+ }
+
+ if ( ACL_FileMergeAcl(NULL, new_filename, acl_name_list, new_aclname, 0) < 0 ) {
+ printf("Failed ACL_FileMergeAcl() test.\n");
+ }
+
+ /* LAS Registration Unit Tests */
+
+ ACL_Init();
+
+ rv = ACL_MethodRegister(NULL, "one", &method);
+ printf("Method one is #%d, rv=%d\n", (int)method, rv);
+
+ rv = ACL_MethodRegister(NULL, "two", &method);
+ printf("Method two is #%d, rv=%d\n", (int)method, rv);
+
+ rv = ACL_MethodRegister(NULL, "one", &method);
+ printf("Method one repeated is #%d, rv=%d\n", (int)method, rv);
+
+ rv = ACL_MethodRegister(NULL, "three", &method);
+ printf("Method three is #%d, rv=%d\n", (int)method, rv);
+
+ rv = ACL_MethodNamesGet(NULL, &names, &cnt);
+
+ for(i = 0; i < cnt; i++) {
+ printf("\tMethod[%d] = \"%s\"\n", i, names[i]);
+ }
+
+ ACL_MethodNamesFree(NULL, names, cnt);
+
+ if (!ACL_MethodIsEqual(NULL, method, method)) {
+ printf("Error comparing methods");
+ }
+
+ if (!ACL_MethodNameIsEqual(NULL, method, "three")) {
+ printf("Error comparing method by name");
+ }
+
+ /* Since LDAP is already registered by ACL_Init, the first number
+ * we'll get is actually 2.
+ */
+ rv = ACL_DbTypeRegister(NULL, "two", parse_dburl, &dbtype);
+ printf("DbType two is #%d, rv=%d\n", (int)dbtype, rv);
+
+ rv = ACL_DbTypeRegister(NULL, "three", parse_dburl, &dbtype);
+ printf("DbType three is #%d, rv=%d\n", (int)dbtype, rv);
+
+ rv = ACL_DbTypeRegister(NULL, "two", parse_dburl, &dbtype);
+ printf("DbType two repeated is #%d, rv=%d\n", (int)dbtype, rv);
+
+ rv = ACL_DbTypeRegister(NULL, "four", parse_dburl, &dbtype);
+ printf("DbType four is #%d, rv=%d\n", (int)dbtype, rv);
+
+ if (!ACL_DbTypeIsEqual(NULL, dbtype, dbtype)) {
+ printf("Error comparing dbtypes\n");
+ }
+
+ if (!ACL_DbTypeNameIsEqual(NULL, dbtype, "four")) {
+ printf("Error comparing dbtype by name\n");
+ }
+
+ rv = ACL_DatabaseRegister(NULL, dbtype, "db1", "url for db1", NULL);
+ if (rv < 0) {
+ printf("ACL_DatabaseRegister failed for db1\n");
+ }
+
+ rv = ACL_DatabaseRegister(NULL, dbtype, "db2", "url for db2", NULL);
+ if (rv < 0) {
+ printf("ACL_DatabaseRegister failed for db2\n");
+ }
+
+ rv = ACL_DatabaseRegister(NULL, dbtype, "db3", "url for db3", NULL);
+ if (rv < 0) {
+ printf("ACL_DatabaseRegister failed for db3\n");
+ }
+
+ rv = ACL_DatabaseNamesGet(NULL, &names, &cnt);
+
+ for(i = 0; i < cnt; i++) {
+ printf("\tDatabase[%d] = \"%s\"\n", i, names[i]);
+ }
+
+ if (ACL_AttrGetterRegister(NULL, "attr", (ACLAttrGetterFn_t)2, (ACLMethod_t)10, (ACLDbType_t)20, ACL_AT_FRONT, NULL)) {
+ printf("Error registering attr getter\n");
+ }
+
+ if (ACL_AttrGetterRegister(NULL, "attr", (ACLAttrGetterFn_t)3, (ACLMethod_t)10, (ACLDbType_t)20, ACL_AT_END, NULL)) {
+ printf("Error registering attr getter\n");
+ }
+
+ if (ACL_AttrGetterRegister(NULL, "attr", (ACLAttrGetterFn_t)1, (ACLMethod_t)10, (ACLDbType_t)20, ACL_AT_FRONT, NULL)) {
+ printf("Error registering attr getter\n");
+ }
+
+ if (ACL_AttrGetterRegister(NULL, "attr", (ACLAttrGetterFn_t)4, (ACLMethod_t)10, (ACLDbType_t)20, ACL_AT_END, NULL)) {
+ printf("Error registering attr getter\n");
+ }
+
+ if (ACL_AttrGetterFind(NULL, "attr", &aglist)) {
+ printf("Error finding attr getter\n");
+ }
+
+ for (i = 0, agptr = ACL_AttrGetterFirst(&aglist);
+ i < 4;
+ i++, agptr = ACL_AttrGetterNext(&aglist, agptr)) {
+
+ if (agptr) {
+ printf("position %d\n", (int)(agptr->fn));
+ }
+ else {
+ printf("***Error: missing getter ***\n");
+ }
+ }
+
+#ifndef XP_WIN32
+ if (ACL_LasRegister(NULL, "test_attr", TestEvalFunc, TestFlushFunc)) {
+ printf("Error registering Test LAS functions\n");
+ }
+ ACL_LasFindEval(NULL, "test_attr", &Eval_funcp);
+ if (Eval_funcp != TestEvalFunc) {
+ printf("Error finding Eval function - expecting %x, got %x\n",
+ TestEvalFunc, Eval_funcp);
+ }
+ ACL_LasFindFlush(NULL, "test_attr", &Flush_funcp);
+ if (Flush_funcp != TestFlushFunc) {
+ printf("Error finding Flush function - expecting %x, got %x\n",
+ TestFlushFunc, Flush_funcp);
+ }
+ ACL_LasFindEval(NULL, "wrong_attr", &Eval_funcp);
+ if (Eval_funcp != NULL) {
+ printf("Error finding Eval function - expecting NULL, got %x\n",
+ Eval_funcp);
+ }
+ ACL_LasFindFlush(NULL, "wrong_attr", &Flush_funcp);
+ if (Flush_funcp != NULL) {
+ printf("Error finding Flush function - expecting NULL, got %x\n",
+ Flush_funcp);
+ }
+#endif /* !XP_WIN32 */
+
+ /* ACL Eval Unit Tests
+ */
+ rights[0] = "http_get";
+ rights[1] = "http_post";
+ rights[2] = NULL;
+
+ eval.subject = NULL;
+ eval.resource = NULL;
+
+ for (i=0; i<10; i++) {
+ sprintf(filename, "aclfile%d", i);
+ eval.acllist = ACL_ParseFile((NSErr_t *)NULL, filename);
+ if ( eval.acllist == NULL ) {
+ printf("Couldn't parse.\n");
+ continue;
+ }
+
+ sprintf(newfilename, "%s.v30", filename);
+ if ( ACL_WriteFile(NULL, newfilename, eval.acllist) < 0) {
+ printf("Couldn't write %s.\n", newfilename);
+ }
+ result = ACL_EvalTestRights(NULL, &eval, &rights[0],
+ http_generic, &bong, &bong_type, &acl_tag, &expr_num);
+ ACL_ListDestroy(NULL, eval.acllist);
+ printf("%s = %d\n\n", filename, result);
+ }
+
+/********************************************************************
+
+ TEST #1
+
+ TEST ACL_ParseString()
+ TEST ACL_WriteFile()
+ TEST ACL_ParseFile()
+ TEST ACL_ListFind()
+
+*********************************************************************/
+ acl_list = ACL_ParseString((NSErr_t *)NULL,
+ "version 3.0; acl > franco;");
+ if ( acl_list != NULL ) {
+ ACL_ListDestroy(NULL, acl_list);
+ printf("Test #1a fails parsed invalid ACL\n");
+ goto skip_test;
+ }
+
+ acl_list = ACL_ParseString((NSErr_t *)NULL,
+ "version 3.0; acl franco; \nallow (read) user=franco;");
+ if ( acl_list == NULL ) {
+ printf("Test #1b fails couldn't parse valid ACL\n");
+ goto skip_test;
+ } else {
+ if ( ACL_WriteFile(NULL, "buffer", acl_list) < 0) {
+ printf("Test #1b, couldn't write %s.\n", "buffer");
+ }
+ ACL_ListDestroy(NULL, acl_list);
+ }
+
+ acl_list = ACL_ParseString((NSErr_t *)NULL,
+ "version 3.0; acl franco; \njunk (read) user=franco;");
+
+ if ( acl_list != NULL ) {
+ printf("Test #1c failed missed syntax error\n");
+ ACL_ListDestroy(NULL, acl_list);
+ goto skip_test;
+ }
+
+ acl_list = ACL_ParseString((NSErr_t *)NULL,
+ "version 3.0; acl franco; \nallow (read) user=franco;");
+
+ if ( acl_list == NULL ) {
+ printf("Test #1d couldn't parse valid ACL\n");
+ } else {
+ ACL_ListDestroy(NULL, acl_list);
+ goto skip_test;
+ }
+
+ acl_list= ACL_ParseFile((NSErr_t *)NULL, "buffer");
+ if ( acl_list == NULL ) {
+ printf("Test #1e, couldn't perform ACL_ParseFile(buffer)\n");
+ goto skip_test;
+ } else {
+ if ( ACL_ListFind(NULL, acl_list, "franco", ACL_CASE_INSENSITIVE) == NULL ) {
+ printf("Test #1e, couldn't find %s in %s.\n", "franco", "buffer");
+ }
+ ACL_ListDestroy(NULL, acl_list);
+ }
+
+/********************************************************************
+
+ TEST #2
+
+ TEST ACL_FileDeleteAcl()
+ TEST ACL_ParseFile()
+ TEST ACL_ListFind()
+
+*********************************************************************/
+ if ( ACL_FileDeleteAcl(NULL, "buffer", "franco", ACL_CASE_INSENSITIVE) < 0) {
+ printf("Test #2, couldn't write %s.\n", "buffer");
+ }
+ acl_list= ACL_ParseFile((NSErr_t *)NULL, "buffer");
+ if ( acl_list == NULL ) {
+ printf("Test #2, couldn't perform ACL_ParseFile(buffer)\n");
+ goto skip_test;
+ } else {
+ if ( ACL_ListFind(NULL, acl_list, "franco", ACL_CASE_INSENSITIVE) ) {
+ printf("Couldn't delete %s from %s.\n", "franco", "buffer");
+ }
+ ACL_ListDestroy(NULL, acl_list);
+ }
+
+/********************************************************************
+
+ TEST #3
+
+ TEST ACL_FileSetAcl()
+ TEST ACL_ParseFile()
+ TEST ACL_ListFind()
+
+*********************************************************************/
+ if ( ACL_FileSetAcl(NULL, "buffer",
+ "version 3.0; acl FileSetAcl; \nallow (read) user=franco;",
+ ACL_CASE_INSENSITIVE)< 0) {
+ printf("Test #3, couldn't ACL_FileSetACL(%s).\n", "FileSetAcl");
+ }
+ if ( ACL_FileSetAcl(NULL, "buffer",
+ "version 3.0; acl franco; \nallow (read) user=franco;",
+ ACL_CASE_INSENSITIVE)< 0) {
+ printf("Test #3, couldn't ACL_FileSetACL(%s).\n", "franco");
+ }
+ acl_list= ACL_ParseFile((NSErr_t *)NULL, "buffer");
+ if ( acl_list == NULL ) {
+ printf("Test #3, couldn't perform ACL_ParseFile(buffer)\n");
+ goto skip_test;
+ } else {
+ if ( ACL_ListFind(NULL, acl_list, "franco", ACL_CASE_INSENSITIVE) == NULL) {
+ printf("Test #3, couldn't set %s in %s.\n", "franco", "buffer");
+ }
+ if ( ACL_ListFind(NULL, acl_list, "filesetacl", ACL_CASE_INSENSITIVE) == NULL) {
+ printf("Test #3, couldn't set %s in %s.\n", "filesetacl", "buffer");
+ }
+ ACL_ListDestroy(NULL, acl_list);
+ }
+
+/********************************************************************
+
+ TEST #4
+
+ TEST ACL_FileRenameAcl()
+ TEST ACL_ParseFile()
+ TEST ACL_ListFind()
+
+*********************************************************************/
+ if ( ACL_FileRenameAcl(NULL, "buffer", "FileSetAcl", "loser", ACL_CASE_INSENSITIVE)< 0) {
+ printf("Test #4, fail ACL_FileRenameACL(filesetacl, loser).\n");
+ }
+ if ( ACL_FileRenameAcl(NULL, "buffer", "franco", "bigdogs",
+ ACL_CASE_INSENSITIVE)< 0) {
+ printf("Test #4, fail ACL_FileRenameACL(franco, bigdogs).\n");
+ }
+ acl_list= ACL_ParseFile((NSErr_t *)NULL, "buffer");
+ if ( acl_list == NULL ) {
+ printf("Test #3, couldn't perform ACL_ParseFile(buffer)\n");
+ goto skip_test;
+ } else {
+ if ( ACL_ListFind(NULL, acl_list, "loser", ACL_CASE_INSENSITIVE) == NULL) {
+ printf("Test #4, fail rename %s in %s.\n", "loser", "buffer");
+ }
+ if ( ACL_ListFind(NULL, acl_list, "bigdogs", ACL_CASE_INSENSITIVE) == NULL) {
+ printf("Test #4, fail rename %s in %s.\n", "bigdogs", "buffer");
+ }
+ if ( ACL_ListGetNameList(NULL, acl_list, &name_list) < 0 ) {
+ printf("Test #4, yikes, the GetNameList failed.\n");
+ } else {
+ for (ii = 0; name_list[ii]; ii++)
+ printf("ACL %s\n", name_list[ii]);
+ ACL_NameListDestroy(NULL, name_list);
+ }
+ ACL_ListDestroy(NULL, acl_list);
+ }
+
+
+
+
+skip_test:
+/********************************************************************
+
+ END
+
+*********************************************************************/
+
+ rights[0] = "html_read";
+ rights[1] = "html_write";
+
+ map_generic[0] = "html_read";
+ map_generic[1] = "html_write";
+ map_generic[2] = "N/A";
+ map_generic[3] = "html_create";
+ map_generic[4] = "html_delete";
+ map_generic[5] = "N/A";
+ map_generic[6] = NULL;
+
+ for (i=10; i<20; i++) {
+ sprintf(filename, "aclfile%d", i);
+ eval.acllist = ACL_ParseFile((NSErr_t *)NULL, filename);
+ if ( eval.acllist == NULL ) {
+ printf("Parse failed.\n");
+ continue;
+ }
+ result = ACL_EvalTestRights(NULL, &eval, &rights[0], map_generic, &bong, &bong_type, &acl_tag, &expr_num);
+ ACL_ListDestroy(NULL, eval.acllist);
+ printf("%s = %d\n\n", filename, result);
+ }
+
+ /*
+ * Program LAS Unit Tests
+ */
+ char *groups[32] = {
+ "http-foo",
+ "http-bar",
+ "http-grog",
+ NULL
+ };
+ char *programs[32] = {
+ "foo, fubar, frobozz",
+ "bar, shoo, fly",
+ "grog, beer",
+ NULL
+ };
+ struct program_groups program_groups;
+ program_groups.groups = groups;
+ program_groups.programs = programs;
+
+ result = LASProgramEval(NULL, "program", CMP_OP_EQ, "http-foo, http-bar,http-grog", &cachable, &las_cookie, (PList_t)"foo", (PList_t)&program_groups, NULL, NULL);
+ printf("program = foo %d\n\n", result);
+
+
+ result = LASProgramEval(NULL, "program", CMP_OP_EQ, "http-foo, http-bar,http-grog", &cachable, &las_cookie, (PList_t)"nomatch", (PList_t)&program_groups, NULL, NULL);
+ printf("program = nomatch %d\n\n", result);
+
+
+ result = LASProgramEval(NULL, "program", CMP_OP_EQ, "http-foo, http-bar,http-grog", &cachable, &las_cookie, (PList_t)"beer", (PList_t)&program_groups, NULL, NULL);
+ printf("program = beer %d\n\n", result);
+
+
+ result = LASProgramEval(NULL, "program", CMP_OP_EQ, "http-foo, http-bar, http-grog", &cachable, &las_cookie, (PList_t)"http-grog", (PList_t)&program_groups, NULL, NULL);
+ printf("program = http-grog %d\n\n", result);
+
+ result = LASProgramEval(NULL, "program", CMP_OP_EQ, "http-foo", &cachable, &las_cookie, (PList_t)"ubar", (PList_t)&program_groups, NULL, NULL);
+ printf("program = ubar %d\n\n", result);
+
+
+ /*
+ * DNS LAS Unit Tests
+ */
+
+ result = LASDnsEval(NULL, "dnsalias", CMP_OP_EQ, "*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dnsalias = *? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dnsalias", CMP_OP_EQ, "aruba.mcom.com brain251.mcom.com", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dnsalias = aruba.mcom.com brain251.mcom.com? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_EQ, "*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns = *? %d\n\n", result);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_NE, "*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns != *? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_EQ, "aruba.mcom.com", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns = aruba.mcom.com? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_EQ, "ai.mit.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns = ai.mit.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_EQ, "*.ai.mit.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns = *.ai.mit.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_EQ, "*.mit.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns = *.mit.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_EQ, "*.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns = *.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_NE, "*.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns != *.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "mistake", CMP_OP_NE, "*.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("mistake != *.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_GT, "*.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns > *.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+
+ /*
+ * IP LAS Unit Tests
+ */
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = *? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_NE, "*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip != *? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "*.*.*.*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = *.*.*.*? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.*? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.*.*.*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.*.*.*? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.*? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.*.*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.*.*? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.*? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.*+255.255.255.255", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.*+255.255.255.255? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.69+255.255.255.254, 123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.69+255.255.255.254, 123.45.67.89? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_NE, "17.34.51.69+255.255.255.254, 123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip != 17.34.51.69+255.255.255.254, 123.45.67.89? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.68, 17.34.51.69", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.68, 17.34.51.69? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.68, 17.34.51.69, 123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.68, 17.34.51.69, 123.45.67.89? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_NE, "17.34.51.68, 17.34.51.69, 123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip != 17.34.51.68, 17.34.51.69, 123.45.67.89? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.68", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.68? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.69", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.69? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.69+255.255.255.254", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.69+255.255.255.254? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.50.69+255.255.254.0", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.50.69+255.255.254.0? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.35.50.69+255.254.0.0", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.35.50.69+255.254.0.0? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "16.35.50.69+254.0.0.0", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 16.35.50.69+254.0.0.0? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 123.45.67.89? %d\n\n", result);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_NE, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip != 123.45.67.89? %d\n\n", result);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_GT, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip > 123.45.67.89? %d\n\n", result);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_LT, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip < 123.45.67.89? %d\n\n", result);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_GE, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip >= 123.45.67.89? %d\n\n", result);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_LE, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip <= 123.45.67.89? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "mistake", CMP_OP_LE, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("mistake <= 123.45.67.89? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+
+ /*
+ * Time of Day unit tests.
+ */
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_EQ, "2120", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time = 2120? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_NE, "2120", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time != 2120? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_EQ, "0700", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time = 0700? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_NE, "0700", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time != 0700? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_EQ, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time = 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_NE, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time != 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_GT, "2120", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time > 2120? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LT, "2120", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time < 2120? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_GT, "0700", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time > 0700? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LT, "0700", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time < 0700? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_GT, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time > 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LT, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time < 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_GE, "2120", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time >= 2120? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LE, "2120", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time <= 2120? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_GE, "0700", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time >= 0700? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LE, "0700", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time <= 0700? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_GE, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time >= 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LE, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time <= 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "mistake", CMP_OP_LE, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("mistake <= 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_EQ, "0800-2200", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time = 0800-2200? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_NE, "0800-2200", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time != 0800-2200? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_EQ, "2200-0800", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time = 2200-0800? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_NE, "2200-0800", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time != 2200-0800? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LE, "2200-0800", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time <= 2200-0800? %d\n\n", result);
+
+
+ /*
+ * Day Of Week Unit Tests
+ */
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "Mon", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= mon? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "tUe", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= tUe? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "weD", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= weD? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "THu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= THu? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "FrI", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= FrI? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "sAT", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= tUe? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "Sun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= Sun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "mon,tuewed,thu,frisatsun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= mon,tuewed,thu,frisatsun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_NE, "mon,tuewed,thu,frisatsun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("!= mon,tuewed,thu,frisatsun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_GT, "Sun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("> Sun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_LT, "Sun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("< Sun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_GE, "Sun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf(">= Sun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_LE, "Sun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("<= Sun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "mistake", CMP_OP_LE, "Sun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("mistake <= Sun? %d\n\n", result);
+
+
+ ACL_Destroy();
+
+ exit(0);
+
+}
diff --git a/lib/libaccess/utest/lasemail.cpp b/lib/libaccess/utest/lasemail.cpp
new file mode 100644
index 00000000..469a315f
--- /dev/null
+++ b/lib/libaccess/utest/lasemail.cpp
@@ -0,0 +1,180 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* lasemail.cpp
+ * This file contains the Email LAS code.
+ */
+
+#include <ldap.h>
+#include <nsacl/aclapi.h>
+
+#define ACL_ATTR_EMAIL "email"
+
+extern "C" {
+extern int LASEmailEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator, char *attr_pattern, ACLCachable_t *cachable, void **LAS_cookie, PList_t subject, PList_t resource, PList_t auth_info, PList_t global_auth);
+extern void LASEmailFlush(void **las_cookie);
+extern int LASEmailModuleInit();
+}
+
+
+/*
+ * LASEmailEval
+ * INPUT
+ * attr_name The string "email" - in lower case.
+ * comparator CMP_OP_EQ or CMP_OP_NE only
+ * attr_pattern A comma-separated list of emails
+ * (we currently support only one e-mail addr)
+ * *cachable Always set to ACL_NOT_CACHABLE.
+ * subject Subject property list
+ * resource Resource property list
+ * auth_info Authentication info, if any
+ * RETURNS
+ * retcode The usual LAS return codes.
+ */
+int LASEmailEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, ACLCachable_t *cachable,
+ void **LAS_cookie, PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth)
+{
+ char *uid;
+ char *email;
+ int rv;
+ LDAP *ld;
+ char *basedn;
+ LDAPMessage *res;
+ int numEntries;
+ char filter[1024];
+ int matched;
+
+ *cachable = ACL_NOT_CACHABLE;
+ *LAS_cookie = (void *)0;
+
+ if (strcmp(attr_name, ACL_ATTR_EMAIL) != 0) {
+ fprintf(stderr, "LASEmailEval called for incorrect attr \"%s\"\n",
+ attr_name);
+ return LAS_EVAL_INVALID;
+ }
+
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ fprintf(stderr, "LASEmailEval called with incorrect comparator %d\n",
+ comparator);
+ return LAS_EVAL_INVALID;
+ }
+
+ if (!strcmp(attr_pattern, "anyone")) {
+ *cachable = ACL_INDEF_CACHABLE;
+ return comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+ }
+
+ /* get the authenticated user name */
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USER, (void **)&uid,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return rv;
+ }
+
+ /* We have an authenticated user */
+ if (!strcmp(attr_pattern, "all")) {
+ return comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+ }
+
+ /* do an ldap lookup for: (& (uid=<user>) (mail=<email>)) */
+ rv = ACL_LDAPDatabaseHandle(errp, NULL, &ld, &basedn);
+
+ if (rv != LAS_EVAL_TRUE) {
+ fprintf(stderr, "unable to get LDAP handle\n");
+ return rv;
+ }
+
+ /* Formulate the filter -- assume single e-mail in attr_pattern */
+ /* If we support multiple comma separated e-mail addresses in the
+ * attr_pattern then the filter will look like:
+ * (& (uid=<user>) (| (mail=<email1>) (mail=<email2>)))
+ */
+ sprintf(filter, "(& (uid=%s) (mail=%s))", uid, attr_pattern);
+
+ rv = ldap_search_s(ld, basedn, LDAP_SCOPE_SUBTREE, filter,
+ 0, 0, &res);
+
+ if (rv != LDAP_SUCCESS)
+ {
+ fprintf(stderr, "ldap_search_s: %s\n", ldap_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+
+ numEntries = ldap_count_entries(ld, res);
+
+ if (numEntries == 1) {
+ /* success */
+ LDAPMessage *entry = ldap_first_entry(ld, res);
+ char *dn = ldap_get_dn(ld, entry);
+
+ fprintf(stderr, "ldap_search_s: Entry found. DN: \"%s\"\n", dn);
+ ldap_memfree(dn);
+ matched = 1;
+ }
+ else if (numEntries == 0) {
+ /* not found -- but not an error */
+ fprintf(stderr, "ldap_search_s: Entry not found. Filter: \"%s\"\n",
+ filter);
+ matched = 0;
+ }
+ else if (numEntries > 0) {
+ /* Found more than one entry! */
+ fprintf(stderr, "ldap_search_s: Found more than one entry. Filter: \"%s\"\n",
+ filter);
+ return LAS_EVAL_FAIL;
+ }
+
+ if (comparator == CMP_OP_EQ) {
+ rv = (matched ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ }
+ else {
+ rv = (matched ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+
+ return rv;
+}
+
+
+/* LASEmailFlush
+ * Deallocates any memory previously allocated by the LAS
+ */
+void
+LASEmailFlush(void **las_cookie)
+{
+ /* do nothing */
+ return;
+}
+
+/* LASEmailModuleInit --
+ * Register the e-mail LAS.
+ *
+ * To load this functions in the web server, compile the file in
+ * "lasemail.so" and add the following lines to the
+ * <ServerRoot>/https-<name>/config/obj.conf file. Be sure to change the
+ * "lasemail.so" portion to the full pathname. E.g. /nshome/lib/lasemail.so.
+ *
+ * Init fn="load-modules" funcs="LASEmailModuleInit" shlib="lasemail.so"
+ * Init fn="acl-register-module" module="lasemail" func="LASEmailModuleInit"
+ */
+int LASEmailModuleInit ()
+{
+ NSErr_t err = NSERRINIT;
+ NSErr_t *errp = &err;
+ int rv;
+
+ rv = ACL_LasRegister(errp, ACL_ATTR_EMAIL, LASEmailEval, LASEmailFlush);
+
+ if (rv < 0) {
+ fprintf(stderr, "ACL_LasRegister failed. Error: %d\n", rv);
+ return rv;
+ }
+
+ return rv;
+}
+
diff --git a/lib/libaccess/utest/onetest.cpp b/lib/libaccess/utest/onetest.cpp
new file mode 100644
index 00000000..3bcccbb1
--- /dev/null
+++ b/lib/libaccess/utest/onetest.cpp
@@ -0,0 +1,47 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <stdio.h>
+#include <netsite.h>
+#include <libaccess/nserror.h>
+#include <base/session.h>
+#include <libaccess/acl.h>
+#include "../aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include <base/plist.h>
+#include <base/ereport.h>
+
+extern ACLListHandle_t *ACL_ParseFile(NSErr_t *errp, char *filename);
+extern ACLEvalDestroyContext(NSErr_t *errp, ACLEvalHandle_t *acleval);
+
+
+main(int arc, char **argv)
+{
+ int result;
+ int cachable;
+ void *las_cookie=NULL;
+ ACLEvalHandle_t eval;
+ char *rights[2];
+ char filename[20];
+ int i;
+ char *bong;
+ char *bong_type;
+ char *acl_tag;
+ int expr_num;
+
+ /* ACL Eval Unit Tests
+ */
+ rights[0] = "read";
+ rights[1] = "write";
+ rights[2] = NULL;
+
+ eval.acllist = ACL_ParseFile((NSErr_t *)NULL, argv[1]);
+ result = ACL_EvalTestRights(NULL, &eval, &rights[0], NULL, &bong, &bong_type, &acl_tag, &expr_num);
+ ACLEvalDestroyContext(NULL, &eval);
+ ACL_ListDestroy(NULL, eval.acllist);
+ printf("%s = %d\n\n", argv[1], result);
+
+}
diff --git a/lib/libaccess/utest/shexp.cpp b/lib/libaccess/utest/shexp.cpp
new file mode 100644
index 00000000..23e9e909
--- /dev/null
+++ b/lib/libaccess/utest/shexp.cpp
@@ -0,0 +1,294 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * shexp.c: shell-like wildcard match routines
+ *
+ *
+ * See shexp.h for public documentation.
+ *
+ * Rob McCool
+ *
+ */
+
+#include "shexp.h"
+#include <ctype.h> /* isalpha, tolower */
+
+
+/* ----------------------------- shexp_valid ------------------------------ */
+
+
+int valid_subexp(char *exp, char stop)
+{
+ register int x,y,t;
+ int nsc,np,tld;
+
+ x=0;nsc=0;tld=0;
+
+ while(exp[x] && (exp[x] != stop)) {
+ switch(exp[x]) {
+ case '~':
+ if(tld) return INVALID_SXP;
+ else ++tld;
+ case '*':
+ case '?':
+ case '^':
+ case '$':
+ ++nsc;
+ break;
+ case '[':
+ ++nsc;
+ if((!exp[++x]) || (exp[x] == ']'))
+ return INVALID_SXP;
+ for(++x;exp[x] && (exp[x] != ']');++x)
+ if(exp[x] == '\\')
+ if(!exp[++x])
+ return INVALID_SXP;
+ if(!exp[x])
+ return INVALID_SXP;
+ break;
+ case '(':
+ ++nsc;np = 0;
+ while(1) {
+ if(exp[++x] == ')')
+ return INVALID_SXP;
+ for(y=x;(exp[y]) && (exp[y] != '|') && (exp[y] != ')');++y)
+ if(exp[y] == '\\')
+ if(!exp[++y])
+ return INVALID_SXP;
+ if(!exp[y])
+ return INVALID_SXP;
+ if(exp[y] == '|')
+ ++np;
+ t = valid_subexp(&exp[x],exp[y]);
+ if(t == INVALID_SXP)
+ return INVALID_SXP;
+ x+=t;
+ if(exp[x] == ')') {
+ if(!np)
+ return INVALID_SXP;
+ break;
+ }
+ }
+ break;
+ case ')':
+ case ']':
+ return INVALID_SXP;
+ case '\\':
+ if(!exp[++x])
+ return INVALID_SXP;
+ default:
+ break;
+ }
+ ++x;
+ }
+ if((!stop) && (!nsc))
+ return NON_SXP;
+ return ((exp[x] == stop) ? x : INVALID_SXP);
+}
+
+NSAPI_PUBLIC int shexp_valid(char *exp) {
+ int x;
+
+ x = valid_subexp(exp, '\0');
+ return (x < 0 ? x : VALID_SXP);
+}
+
+
+/* ----------------------------- shexp_match ----------------------------- */
+
+
+#define MATCH 0
+#define NOMATCH 1
+#define ABORTED -1
+
+int _shexp_match(char *str, char *exp);
+
+int handle_union(char *str, char *exp)
+{
+ char *e2 = (char *) MALLOC(sizeof(char)*strlen(exp));
+ register int t,p2,p1 = 1;
+ int cp;
+
+ while(1) {
+ for(cp=1;exp[cp] != ')';cp++)
+ if(exp[cp] == '\\')
+ ++cp;
+ for(p2 = 0;(exp[p1] != '|') && (p1 != cp);p1++,p2++) {
+ if(exp[p1] == '\\')
+ e2[p2++] = exp[p1++];
+ e2[p2] = exp[p1];
+ }
+ for(t=cp+1;(e2[p2] = exp[t]);++t,++p2);
+ if(_shexp_match(str,e2) == MATCH) {
+ FREE(e2);
+ return MATCH;
+ }
+ if(p1 == cp) {
+ FREE(e2);
+ return NOMATCH;
+ }
+ else ++p1;
+ }
+}
+
+
+int _shexp_match(char *str, char *exp)
+{
+ register int x,y;
+ int ret,neg;
+
+ ret = 0;
+ for(x=0,y=0;exp[y];++y,++x) {
+ if((!str[x]) && (exp[y] != '(') && (exp[y] != '$') && (exp[y] != '*'))
+ ret = ABORTED;
+ else {
+ switch(exp[y]) {
+ case '$':
+ if( (str[x]) )
+ ret = NOMATCH;
+ else
+ --x; /* we don't want loop to increment x */
+ break;
+ case '*':
+ while(exp[++y] == '*');
+ if(!exp[y])
+ return MATCH;
+ while(str[x]) {
+ switch(_shexp_match(&str[x++],&exp[y])) {
+ case NOMATCH:
+ continue;
+ case ABORTED:
+ ret = ABORTED;
+ break;
+ default:
+ return MATCH;
+ }
+ break;
+ }
+ if((exp[y] == '$') && (exp[y+1] == '\0') && (!str[x]))
+ return MATCH;
+ else
+ ret = ABORTED;
+ break;
+ case '[':
+ if((neg = ((exp[++y] == '^') && (exp[y+1] != ']'))))
+ ++y;
+
+ if((isalnum(exp[y])) && (exp[y+1] == '-') &&
+ (isalnum(exp[y+2])) && (exp[y+3] == ']'))
+ {
+ int start = exp[y], end = exp[y+2];
+
+ /* Droolproofing for pinheads not included */
+ if(neg ^ ((str[x] < start) || (str[x] > end))) {
+ ret = NOMATCH;
+ break;
+ }
+ y+=3;
+ }
+ else {
+ int matched;
+
+ for(matched=0;exp[y] != ']';y++)
+ matched |= (str[x] == exp[y]);
+ if(neg ^ (!matched))
+ ret = NOMATCH;
+ }
+ break;
+ case '(':
+ return handle_union(&str[x],&exp[y]);
+ break;
+ case '?':
+ break;
+ case '\\':
+ ++y;
+ default:
+#ifdef XP_UNIX
+ if(str[x] != exp[y])
+#else /* XP_WIN32 */
+ if(strnicmp(str + x, exp + y, 1))
+#endif /* XP_WIN32 */
+ ret = NOMATCH;
+ break;
+ }
+ }
+ if(ret)
+ break;
+ }
+ return (ret ? ret : (str[x] ? NOMATCH : MATCH));
+}
+
+NSAPI_PUBLIC int shexp_match(char *str, char *xp) {
+ register int x;
+ char *exp = STRDUP(xp);
+
+ for(x=strlen(exp)-1;x;--x) {
+ if((exp[x] == '~') && (exp[x-1] != '\\')) {
+ exp[x] = '\0';
+ if(_shexp_match(str,&exp[++x]) == MATCH)
+ goto punt;
+ break;
+ }
+ }
+ if(_shexp_match(str,exp) == MATCH) {
+ FREE(exp);
+ return 0;
+ }
+
+ punt:
+ FREE(exp);
+ return 1;
+}
+
+
+/* ------------------------------ shexp_cmp ------------------------------- */
+
+
+NSAPI_PUBLIC int shexp_cmp(char *str, char *exp)
+{
+ switch(shexp_valid(exp)) {
+ case INVALID_SXP:
+ return -1;
+ case NON_SXP:
+#ifdef XP_UNIX
+ return (strcmp(exp,str) ? 1 : 0);
+#else /* XP_WIN32 */
+ return (stricmp(exp,str) ? 1 : 0);
+#endif /* XP_WIN32 */
+ default:
+ return shexp_match(str, exp);
+ }
+}
+
+
+/* ---------------------------- shexp_casecmp ----------------------------- */
+
+
+NSAPI_PUBLIC int shexp_casecmp(char *str, char *exp)
+{
+ char *lstr = STRDUP(str), *lexp = STRDUP(exp), *t;
+ int ret;
+
+ for(t = lstr; *t; t++)
+ if(isalpha(*t)) *t = tolower(*t);
+ for(t = lexp; *t; t++)
+ if(isalpha(*t)) *t = tolower(*t);
+
+ switch(shexp_valid(lexp)) {
+ case INVALID_SXP:
+ ret = -1;
+ break;
+ case NON_SXP:
+ ret = (strcmp(lexp, lstr) ? 1 : 0);
+ break;
+ default:
+ ret = shexp_match(lstr, lexp);
+ }
+ FREE(lstr);
+ FREE(lexp);
+ return ret;
+}
+
diff --git a/lib/libaccess/utest/shexp.h b/lib/libaccess/utest/shexp.h
new file mode 100644
index 00000000..edc91842
--- /dev/null
+++ b/lib/libaccess/utest/shexp.h
@@ -0,0 +1,131 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * shexp.h: Defines and prototypes for shell exp. match routines
+ *
+ *
+ * This routine will match a string with a shell expression. The expressions
+ * accepted are based loosely on the expressions accepted by zsh.
+ *
+ * o * matches anything
+ * o ? matches one character
+ * o \ will escape a special character
+ * o $ matches the end of the string
+ * o [abc] matches one occurence of a, b, or c. The only character that needs
+ * to be escaped in this is ], all others are not special.
+ * o [a-z] matches any character between a and z
+ * o [^az] matches any character except a or z
+ * o ~ followed by another shell expression will remove any pattern
+ * matching the shell expression from the match list
+ * o (foo|bar) will match either the substring foo, or the substring bar.
+ * These can be shell expressions as well.
+ *
+ * The public interface to these routines is documented below.
+ *
+ * Rob McCool
+ *
+ */
+
+#ifndef SHEXP_H
+#define SHEXP_H
+
+/*
+ * Requires that the macro MALLOC be set to a "safe" malloc that will
+ * exit if no memory is available. If not under MCC httpd, define MALLOC
+ * to be the real malloc and play with fire, or make your own function.
+ */
+
+#include "../netsite.h"
+
+#include <ctype.h> /* isalnum */
+#include <string.h> /* strlen */
+
+
+/*
+ * Wrappers for shexp/regexp
+ *
+ * Portions of code that explicitly want to have either shexp's
+ * or regexp's should call those functions directly.
+ *
+ * Common code bases for multiple products should use the following
+ * macros instead to use either shell or regular expressions,
+ * depending on the flavor chosen for a given server.
+ *
+ */
+#if defined(MCC_PROXY) && defined(USE_REGEX)
+
+#include "base/regexp.h"
+
+#define WILDPAT_VALID(exp) regexp_valid(exp)
+#define WILDPAT_MATCH(str, exp) regexp_match(str, exp)
+#define WILDPAT_CMP(str, exp) regexp_cmp(str, exp)
+#define WILDPAT_CASECMP(str, exp) regexp_casecmp(str, exp)
+
+#else /* HTTP servers */
+
+#define WILDPAT_VALID(exp) shexp_valid(exp)
+#define WILDPAT_MATCH(str, exp) shexp_match(str, exp)
+#define WILDPAT_CMP(str, exp) shexp_cmp(str, exp)
+#define WILDPAT_CASECMP(str, exp) shexp_casecmp(str, exp)
+
+#endif
+
+
+/* --------------------------- Public routines ---------------------------- */
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ * shexp_valid takes a shell expression exp as input. It returns:
+ *
+ * NON_SXP if exp is a standard string
+ * INVALID_SXP if exp is a shell expression, but invalid
+ * VALID_SXP if exp is a valid shell expression
+ */
+
+#define NON_SXP -1
+#define INVALID_SXP -2
+#define VALID_SXP 1
+
+/* and generic shexp/regexp versions */
+#define NON_WILDPAT NON_SXP
+#define INVALID_WILDPAT INVALID_SXP
+#define VALID_WILDPAT VALID_SXP
+
+/* and regexp versions */
+#define NON_REGEXP NON_SXP
+#define INVALID_REGEXP INVALID_SXP
+#define VALID_REGEXP VALID_SXP
+
+
+NSAPI_PUBLIC int shexp_valid(char *exp);
+
+/*
+ * shexp_match
+ *
+ * Takes a prevalidated shell expression exp, and a string str.
+ *
+ * Returns 0 on match and 1 on non-match.
+ */
+
+NSAPI_PUBLIC int shexp_match(char *str, char *exp);
+
+
+/*
+ * shexp_cmp
+ *
+ * Same as above, but validates the exp first. 0 on match, 1 on non-match,
+ * -1 on invalid exp. shexp_casecmp does the same thing but is case
+ * insensitive.
+ */
+
+NSAPI_PUBLIC int shexp_cmp(char *str, char *exp);
+NSAPI_PUBLIC int shexp_casecmp(char *str, char *exp);
+
+NSPR_END_EXTERN_C
+
+#endif
+
diff --git a/lib/libaccess/utest/test.ref b/lib/libaccess/utest/test.ref
new file mode 100644
index 00000000..d5207382
--- /dev/null
+++ b/lib/libaccess/utest/test.ref
@@ -0,0 +1,234 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+Failed ACL_FileMergeFile() test.
+Method one is #1, rv=0
+Method two is #2, rv=0
+Method one repeated is #1, rv=0
+Method three is #3, rv=0
+ Method[0] = "two"
+ Method[1] = "three"
+ Method[2] = "one"
+DbType two is #2, rv=0
+DbType three is #3, rv=0
+DbType two repeated is #2, rv=0
+DbType four is #4, rv=0
+ Database[0] = "db2"
+ Database[1] = "db1"
+ Database[2] = "db3"
+position 1
+position 2
+position 3
+position 4
+aclfile0 = 0
+
+aclfile1 = 1
+
+aclfile2 = 1
+
+aclfile3 = 1
+
+aclfile4 = 0
+
+aclfile5 = 0
+
+aclfile6 = 0
+
+aclfile7 = 1
+
+aclfile8 = 0
+
+aclfile9 = 3
+
+ACL file: internal-buffer
+Syntax error at line: 1, token: >
+ACL file: internal-buffer
+Syntax error at line: 2, token: junk
+aclfile10 = 1
+
+aclfile11 = 1
+
+aclfile12 = 0
+
+aclfile13 = 0
+
+aclfile14 = 0
+
+aclfile15 = 1
+
+aclfile16 = 1
+
+aclfile17 = 0
+
+aclfile18 = 0
+
+aclfile19 = 1
+
+program = foo -1
+
+program = nomatch -2
+
+program = beer -1
+
+program = http-grog -2
+
+program = ubar -2
+
+dnsalias = *? -1
+
+dnsalias = aruba.mcom.com brain251.mcom.com? -1
+
+dns = *? -1
+
+dns != *? -2
+
+dns = aruba.mcom.com? -1
+
+dns = ai.mit.edu? -2
+
+dns = *.ai.mit.edu? -2
+
+dns = *.mit.edu? -2
+
+dns = *.edu? -2
+
+dns != *.edu? -1
+
+mistake != *.edu? -5
+
+dns > *.edu? -5
+
+ip = *? -1
+
+ip != *? -2
+
+ip = *.*.*.*? -1
+
+ip = 17.*? -1
+
+ip = 17.*.*.*? -1
+
+ip = 17.34.*? -1
+
+ip = 17.34.*.*? -1
+
+ip = 17.34.51.*? -1
+
+ip = 17.34.51.*+255.255.255.255? -1
+
+ip = 17.34.51.69+255.255.255.254, 123.45.67.89? -1
+
+ip != 17.34.51.69+255.255.255.254, 123.45.67.89? -2
+
+ip = 17.34.51.68, 17.34.51.69? -1
+
+ip = 17.34.51.68, 17.34.51.69, 123.45.67.89? -1
+
+ip != 17.34.51.68, 17.34.51.69, 123.45.67.89? -2
+
+ip = 17.34.51.68? -1
+
+ip = 17.34.51.69? -2
+
+ip = 17.34.51.69+255.255.255.254? -1
+
+ip = 17.34.50.69+255.255.254.0? -1
+
+ip = 17.35.50.69+255.254.0.0? -1
+
+ip = 16.35.50.69+254.0.0.0? -1
+
+ip = 123.45.67.89? -2
+
+ip != 123.45.67.89? -1
+
+ip > 123.45.67.89? -5
+
+ip < 123.45.67.89? -5
+
+ip >= 123.45.67.89? -5
+
+ip <= 123.45.67.89? -5
+
+mistake <= 123.45.67.89? -5
+
+time = 2120? -1
+
+time != 2120? -2
+
+time = 0700? -2
+
+time != 0700? -1
+
+time = 2400? -2
+
+time != 2400? -1
+
+time > 2120? -2
+
+time < 2120? -2
+
+time > 0700? -1
+
+time < 0700? -2
+
+time > 2400? -2
+
+time < 2400? -1
+
+time >= 2120? -1
+
+time <= 2120? -1
+
+time >= 0700? -1
+
+time <= 0700? -2
+
+time >= 2400? -2
+
+time <= 2400? -1
+
+mistake <= 2400? -5
+
+time = 0800-2200? -1
+
+time != 0800-2200? -2
+
+time = 2200-0800? -2
+
+time != 2200-0800? -1
+
+time <= 2200-0800? -5
+
+= mon? -1
+
+= tUe? -2
+
+= weD? -2
+
+= THu? -2
+
+= FrI? -2
+
+= tUe? -2
+
+= Sun? -2
+
+= mon,tuewed,thu,frisatsun? -1
+
+!= mon,tuewed,thu,frisatsun? -2
+
+> Sun? -5
+
+< Sun? -5
+
+>= Sun? -5
+
+<= Sun? -5
+
+mistake <= Sun? -5
+
diff --git a/lib/libaccess/utest/testmain.cpp b/lib/libaccess/utest/testmain.cpp
new file mode 100644
index 00000000..4da14cee
--- /dev/null
+++ b/lib/libaccess/utest/testmain.cpp
@@ -0,0 +1,52 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * ACL parser unit test program
+ */
+
+#include <stdio.h>
+#include <netsite.h>
+#include <libaccess/acl.h>
+#include <libaccess/nserror.h>
+#include "../aclpriv.h"
+#include <libaccess/aclproto.h>
+
+main(int argc, char **argv)
+{
+
+ACLListHandle_t *acllist;
+int ii;
+char filename[255];
+ACLWrapper_t *wrap;
+ACLExprHandle_t *expr;
+
+ if ( argc < 2 ) {
+ fprintf(stderr, "usage: aclparse <filenames>\n");
+ exit(1);
+ }
+ for (ii = 1; ii < argc; ii++ ) {
+ acllist = ACL_ParseFile(NULL, argv[ii]);
+ if ( acllist == NULL ) {
+ printf("Failed to parse ACL.\n");
+
+ } else {
+ for (wrap = acllist->acl_list_head; wrap;
+ wrap = wrap->wrap_next) {
+ for (expr=wrap->acl->expr_list_head;
+ expr;
+ expr = expr->expr_next ) {
+ ACL_ExprDisplay(expr);
+ }
+ }
+ }
+
+
+ sprintf(filename, "%s.v30", argv[ii]);
+ ACL_WriteFile(NULL, filename, acllist);
+ ACL_ListDestroy( acllist );
+ }
+
+}
diff --git a/lib/libaccess/utest/twotest.cpp b/lib/libaccess/utest/twotest.cpp
new file mode 100644
index 00000000..2d4fb503
--- /dev/null
+++ b/lib/libaccess/utest/twotest.cpp
@@ -0,0 +1,57 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <stdio.h>
+#include <netsite.h>
+#include <base/session.h>
+#include <base/plist.h>
+#include <base/ereport.h>
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include "../aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+
+
+extern ACLListHandle_t *ACL_ParseFile(NSErr_t *errp, char *filename);
+extern ACLEvalDestroyContext(NSErr_t *errp, ACLEvalHandle_t *acleval);
+
+main(int arc, char **argv)
+{
+ int result;
+ int cachable;
+ void *las_cookie=NULL;
+ ACLEvalHandle_t eval;
+ char *rights[2];
+ char *map_generic[7];
+ char filename[20];
+ int i;
+ char *bong;
+ char *bong_type;
+ char *acl_tag;
+ int expr_num;
+
+ /* ACL Eval Unit Tests
+ */
+
+ rights[0] = "html_read";
+ rights[1] = "html_write";
+ rights[2] = NULL;
+
+ map_generic[0] = "html_read";
+ map_generic[1] = "html_write";
+ map_generic[2] = "N/A";
+ map_generic[3] = "html_create";
+ map_generic[4] = "html_delete";
+ map_generic[5] = "N/A";
+ map_generic[6] = NULL;
+
+ eval.acllist = ACL_ParseFile((NSErr_t *)NULL, argv[1]);
+ result = ACL_EvalTestRights(NULL, &eval, &rights[0], map_generic, &bong, &bong_type, &acl_tag, &expr_num);
+ ACLEvalDestroyContext(NULL, &eval);
+ ACL_ListDestroy(NULL, eval.acllist);
+ printf("%s = %d\n\n", argv[1], result);
+
+}
diff --git a/lib/libaccess/utest/ustubs.cpp b/lib/libaccess/utest/ustubs.cpp
new file mode 100644
index 00000000..ccfa3108
--- /dev/null
+++ b/lib/libaccess/utest/ustubs.cpp
@@ -0,0 +1,283 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <sys/types.h>
+#include <malloc.h>
+#include <string.h>
+#include <base/crit.h>
+#include <base/plist.h>
+
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include "../aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/ldapacl.h>
+#include <ldaputil/dbconf.h>
+#ifdef NSPR20
+#include <prprf.h>
+#else
+#include <nspr/prprf.h>
+#endif
+
+NSPR_BEGIN_EXTERN_C
+extern char * ACL_Program;
+extern int conf_getglobals();
+extern int SPconf_getglobals();
+extern int ereport(int, char*, ...);
+extern int SPereport(int, char*, ...);
+extern char * GetAdminLanguage(void);
+extern char * XP_GetStringFromDatabase(char *strLibraryName, char *strLanguage, int iToken);
+extern void ACL_Restart(void *cntlData);
+extern int XP_SetError();
+extern int XP_GetError();
+extern int acl_usr_cache_init();
+extern int acl_usr_cache_set_group();
+extern int acl_usr_cache_group_check();
+extern int sema_destroy();
+extern char *ldapu_err2string(int err);
+extern int ACL_CacheFlush(void);
+NSPR_END_EXTERN_C
+
+static char errbuf[10];
+
+char *
+ldapu_err2string(int err)
+{
+ sprintf(errbuf, "%d", err);
+ return errbuf;
+}
+
+
+void init_ldb_rwlock ()
+{
+}
+
+sema_destroy()
+{
+ return 0;
+}
+
+#ifdef notdef
+char *system_errmsg()
+{
+ static char errmsg[1024];
+
+ sprintf(errmsg, "Stubbed system_errmsg");
+ return errmsg;
+}
+#endif
+
+int
+ACL_CacheFlushRegister(AclCacheFlushFunc_t flush_func)
+{
+ return 0;
+}
+
+acl_usr_cache_init()
+{
+ return 0;
+}
+
+acl_usr_cache_group_check()
+{
+ return 0;
+}
+
+acl_usr_cache_set_group()
+{
+ return 0;
+}
+
+XP_SetError()
+{
+ return 0;
+}
+
+XP_GetError()
+{
+ return 0;
+}
+
+CRITICAL
+crit_init()
+{
+ return (CRITICAL)1;
+}
+
+void
+crit_enter(CRITICAL c)
+{
+ return;
+}
+
+void
+crit_exit(CRITICAL c)
+{
+ return;
+}
+
+void
+crit_terminate(CRITICAL c)
+{
+ return;
+}
+
+int crit_owner_is_me(CRITICAL id)
+{
+ return 1;
+}
+
+symTableFindSym()
+{
+ return 0;
+}
+
+int
+ldap_auth_uid_groupid(LDAP *ld, char *uid, char *groupid,
+ char *base)
+{
+ return 0;
+}
+
+LDAP *
+init_ldap (char *host, int port, int use_ssl)
+{
+ return (LDAP *)"init_ldap_stub";
+}
+
+int ACL_LDAPDatabaseHandle (NSErr_t *errp, const char *dbname, LDAP **ld,
+ char **basedn)
+{
+ *ld = (LDAP *)"ACL_LDAPDatabaseHandle_stub";
+ if (basedn) *basedn = strdup("unknown basedn");
+ return LAS_EVAL_TRUE;
+}
+
+#ifdef notdef
+NSEFrame_t * nserrGenerate(NSErr_t * errp, long retcode, long errorid,
+ char * program, int errc, ...)
+{
+ return 0;
+}
+#endif
+
+char * ACL_Program;
+
+char *
+LASUserGetUser()
+{
+ return "hmiller";
+}
+
+LASIpGetIp()
+{
+ return(0x11223344);
+}
+
+LASDnsGetDns(char **dnsv)
+{
+ *dnsv = "aruba.mcom.com";
+ return 0;
+}
+
+int
+ACL_DestroyList()
+{
+return(0);
+}
+
+aclCheckHosts()
+{
+return(0);
+}
+
+aclCheckUsers()
+{
+return(0);
+}
+
+char *LASGroupGetUser()
+{
+ return("hmiller");
+}
+
+int
+SPconf_getglobals()
+{
+ return 0;
+}
+
+int
+conf_getglobals()
+{
+ return 0;
+}
+
+int
+SPereport(int degree, char *fmt, ...)
+{
+ va_list args;
+ char errstr[1024];
+
+ va_start(args, fmt);
+ PR_vsnprintf(&errstr[0], sizeof(errstr), fmt, args);
+ printf("%s", errstr);
+ va_end(args);
+ return 0;
+}
+
+int
+ereport(int degree, char *fmt, ...)
+{
+ va_list args;
+ char errstr[1024];
+
+ va_start(args, fmt);
+ PR_vsnprintf(&errstr[0], sizeof(errstr), fmt, args);
+ printf("%s", errstr);
+ va_end(args);
+ return 0;
+}
+
+#ifdef notdef
+int dbconf_read_config_file (const char *file, DBConfInfo_t **conf_info_out)
+{
+ return 0;
+}
+#endif
+
+char *
+GetAdminLanguage(void)
+{
+ return "";
+}
+
+static char errstr[1024];
+
+char *
+XP_GetStringFromDatabase(char *strLibraryName, char *strLanguage, int iToken)
+{
+ sprintf(errstr, "XP_GetAdminStr called for error %d\n", iToken);
+ return errstr;
+}
+
+void
+ACL_Restart(void * cntlData)
+{
+ return;
+}
+
+NSAPI_PUBLIC int
+parse_ldap_url(NSErr_t *errp, ACLDbType_t dbtype, const char *name, const char
+*url, PList_t plist, void **db)
+{
+ return 0;
+}
+
+int
+ACL_CacheFlush(void)
+{
+ return 0;
+}
diff --git a/lib/libaccess/winnt.l b/lib/libaccess/winnt.l
new file mode 100644
index 00000000..ce72b535
--- /dev/null
+++ b/lib/libaccess/winnt.l
@@ -0,0 +1,762 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <stdio.h>
+# define U(x) x
+# define NLSTATE yyprevious=YYNEWLINE
+# define BEGIN yybgin = yysvec + 1 +
+# define INITIAL 0
+# define YYLERR yysvec
+# define YYSTATE (yyestate-yysvec-1)
+# define YYOPTIM 1
+# define YYLMAX BUFSIZ
+#ifndef __cplusplus
+# define output(c) (void)putc(c,yyout)
+#else
+# define lex_output(c) (void)putc(c,yyout)
+#endif
+
+#if defined(__cplusplus) || defined(__STDC__)
+
+#if defined(__cplusplus) && defined(__EXTERN_C__)
+extern "C" {
+#endif
+ int yyback(int *, int);
+ int yyinput(void);
+ int yylook(void);
+ void yyoutput(int);
+ int yyracc(int);
+ int yyreject(void);
+ void yyunput(int);
+ int yylex(void);
+#ifdef YYLEX_E
+ void yywoutput(wchar_t);
+ wchar_t yywinput(void);
+#endif
+#ifndef yyless
+ void yyless(int);
+#endif
+#ifndef yywrap
+ int yywrap(void);
+#endif
+#ifdef LEXDEBUG
+ void allprint(char);
+ void sprint(char *);
+#endif
+#if defined(__cplusplus) && defined(__EXTERN_C__)
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void exit(int);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+# define unput(c) {yytchar= (c);if(yytchar=='\n')yylineno--;*yysptr++=yytchar;}
+# define yymore() (yymorfg=1)
+#ifndef __cplusplus
+# define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)
+#else
+# define lex_input() (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)
+#endif
+#define ECHO fprintf(yyout, "%s",yytext)
+# define REJECT { nstr = yyreject(); goto yyfussy;}
+int yyleng; extern char yytext[];
+int yymorfg;
+extern char *yysptr, yysbuf[];
+int yytchar;
+FILE *yyin = NULL, *yyout = NULL;
+extern int yylineno;
+struct yysvf {
+ struct yywork *yystoff;
+ struct yysvf *yyother;
+ int *yystops;};
+struct yysvf *yyestate;
+extern struct yysvf yysvec[], *yybgin;
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include "y.tab.h"
+#include "libaccess/ava.h"
+/*#include "netsite.h" */
+
+int linenum = 1;
+int first_time = 1;
+int old_state;
+int num_nested_comments = 0;
+
+extern AVAEntry tempEntry;
+extern AVATable entryTable;
+
+void strip_quotes(void);
+
+# define COMMENT 2
+# define NORM 4
+# define DEFINES 6
+# define DEF_TYPE 8
+# define YYNEWLINE 10
+yylex(){
+int nstr; extern int yyprevious;
+
+ if (yyin == NULL) yyin = stdin;
+ if (yyout == NULL) yyout = stdout;
+ if (first_time) {
+ BEGIN NORM;
+ first_time = tempEntry.numOrgs = 0;
+ old_state = NORM;
+ tempEntry.userid = 0;
+ tempEntry.country = 0;
+ tempEntry.CNEntry = 0;
+ tempEntry.email = 0;
+ tempEntry.locality = 0;
+ tempEntry.state = 0;
+ entryTable.numEntries = 0;
+ }
+#ifdef __cplusplus
+/* to avoid CC and lint complaining yyfussy not being used ...*/
+static int __lex_hack = 0;
+if (__lex_hack) goto yyfussy;
+#endif
+while((nstr = yylook()) >= 0)
+yyfussy: switch(nstr){
+case 0:
+if(yywrap()) return(0); break;
+case 1:
+
+# line 58 "avascan.l"
+ {BEGIN COMMENT; num_nested_comments++;}
+break;
+case 2:
+
+# line 59 "avascan.l"
+ {num_nested_comments--;
+ if (!num_nested_comments) BEGIN old_state;}
+break;
+case 3:
+
+# line 61 "avascan.l"
+ {;}
+break;
+case 4:
+
+# line 63 "avascan.l"
+ {yylval.string = system_strdup(yytext);
+ return USER_ID;}
+break;
+case 5:
+
+# line 65 "avascan.l"
+{BEGIN DEF_TYPE;
+ old_state = DEF_TYPE;}
+break;
+case 6:
+
+# line 68 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_C; }
+break;
+case 7:
+
+# line 70 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_CO;}
+break;
+case 8:
+
+# line 72 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_OU;}
+break;
+case 9:
+
+# line 74 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_CN;}
+break;
+case 10:
+
+# line 76 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_L;}
+break;
+case 11:
+
+# line 78 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_E;}
+break;
+case 12:
+
+# line 80 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_ST;}
+break;
+case 13:
+
+# line 82 "avascan.l"
+ {BEGIN NORM;old_state = NORM;}
+break;
+case 14:
+
+# line 84 "avascan.l"
+ {return EQ_SIGN;}
+break;
+case 15:
+
+# line 85 "avascan.l"
+ {BEGIN DEF_TYPE; old_state = DEF_TYPE;
+ strip_quotes();
+ return DEF_ID;}
+break;
+case 16:
+
+# line 89 "avascan.l"
+ {;}
+break;
+case 17:
+
+# line 90 "avascan.l"
+ {linenum++;}
+break;
+case 18:
+
+# line 91 "avascan.l"
+ {yyerror("Bad input character");}
+break;
+case -1:
+break;
+default:
+(void)fprintf(yyout,"bad switch yylook %d",nstr);
+} return(0); }
+/* end of yylex */
+
+int yywrap () {
+ return 1;
+}
+
+void strip_quotes(void) {
+ yytext[strlen(yytext)-1]= '\0';
+ yylval.string = system_strdup(&yytext[1]);
+}
+int yyvstop[] = {
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+18,
+0,
+
+16,
+18,
+0,
+
+17,
+0,
+
+18,
+0,
+
+3,
+18,
+0,
+
+3,
+16,
+18,
+0,
+
+3,
+18,
+0,
+
+3,
+18,
+0,
+
+4,
+18,
+0,
+
+18,
+0,
+
+18,
+0,
+
+14,
+18,
+0,
+
+6,
+18,
+0,
+
+11,
+18,
+0,
+
+10,
+18,
+0,
+
+7,
+18,
+0,
+
+18,
+0,
+
+13,
+18,
+0,
+
+16,
+0,
+
+1,
+0,
+
+2,
+0,
+
+4,
+0,
+
+5,
+0,
+
+15,
+0,
+
+9,
+0,
+
+8,
+0,
+
+12,
+0,
+0};
+# define YYTYPE unsigned char
+struct yywork { YYTYPE verify, advance; } yycrank[] = {
+0,0, 0,0, 1,11, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 1,12, 1,13,
+0,0, 3,15, 12,29, 0,0,
+20,33, 0,0, 0,0, 0,0,
+0,0, 3,16, 3,13, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 9,11, 0,0, 1,11,
+0,0, 12,29, 7,21, 20,33,
+8,21, 9,12, 9,13, 14,30,
+0,0, 1,11, 3,15, 4,17,
+1,14, 1,11, 2,14, 7,14,
+4,18, 8,14, 3,17, 5,19,
+3,15, 17,31, 5,14, 3,18,
+3,15, 6,19, 10,14, 21,35,
+6,14, 7,22, 9,11, 8,22,
+0,0, 5,20, 0,0, 21,35,
+21,35, 0,0, 0,0, 6,20,
+9,11, 0,0, 0,0, 9,14,
+9,11, 23,37, 10,23, 0,0,
+10,24, 27,39, 26,38, 0,0,
+0,0, 0,0, 0,0, 10,25,
+0,0, 0,0, 10,26, 0,0,
+21,36, 0,0, 10,27, 9,23,
+0,0, 9,24, 0,0, 0,0,
+0,0, 0,0, 21,35, 0,0,
+9,25, 0,0, 21,35, 9,26,
+0,0, 0,0, 0,0, 9,27,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 20,34, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 19,32, 0,0, 0,0,
+10,28, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 9,28, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+0,0, 0,0, 0,0, 0,0,
+19,32, 0,0, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+0,0};
+struct yysvf yysvec[] = {
+0, 0, 0,
+yycrank+-1, 0, yyvstop+1,
+yycrank+-3, yysvec+1, yyvstop+3,
+yycrank+-12, 0, yyvstop+5,
+yycrank+-5, yysvec+3, yyvstop+7,
+yycrank+-11, yysvec+1, yyvstop+9,
+yycrank+-17, yysvec+1, yyvstop+11,
+yycrank+-4, yysvec+1, yyvstop+13,
+yycrank+-6, yysvec+1, yyvstop+15,
+yycrank+-32, 0, yyvstop+17,
+yycrank+-15, yysvec+9, yyvstop+19,
+yycrank+0, 0, yyvstop+21,
+yycrank+5, 0, yyvstop+23,
+yycrank+0, 0, yyvstop+26,
+yycrank+1, 0, yyvstop+28,
+yycrank+0, 0, yyvstop+30,
+yycrank+0, yysvec+12, yyvstop+33,
+yycrank+10, 0, yyvstop+37,
+yycrank+0, yysvec+14, yyvstop+40,
+yycrank+93, 0, yyvstop+43,
+yycrank+7, 0, yyvstop+46,
+yycrank+-62, 0, yyvstop+48,
+yycrank+0, 0, yyvstop+50,
+yycrank+3, 0, yyvstop+53,
+yycrank+0, 0, yyvstop+56,
+yycrank+0, 0, yyvstop+59,
+yycrank+1, 0, yyvstop+62,
+yycrank+1, 0, yyvstop+65,
+yycrank+0, 0, yyvstop+67,
+yycrank+0, yysvec+12, yyvstop+70,
+yycrank+0, 0, yyvstop+72,
+yycrank+0, 0, yyvstop+74,
+yycrank+0, yysvec+19, yyvstop+76,
+yycrank+0, yysvec+20, 0,
+yycrank+0, 0, yyvstop+78,
+yycrank+0, yysvec+21, 0,
+yycrank+0, 0, yyvstop+80,
+yycrank+0, 0, yyvstop+82,
+yycrank+0, 0, yyvstop+84,
+yycrank+0, 0, yyvstop+86,
+0, 0, 0};
+struct yywork *yytop = yycrank+215;
+struct yysvf *yybgin = yysvec+1;
+char yymatch[] = {
+ 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 9, 10, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 9, 1, 34, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 44, 1, 1, 1,
+ 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 1, 1, 1, 1, 1, 1,
+ 1, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 1, 1, 1, 1, 44,
+ 1, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+0};
+char yyextra[] = {
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0};
+/* Copyright (c) 1989 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#pragma ident "@(#)ncform 6.7 93/06/07 SMI"
+
+int yylineno =1;
+# define YYU(x) x
+# define NLSTATE yyprevious=YYNEWLINE
+char yytext[YYLMAX];
+struct yysvf *yylstate [YYLMAX], **yylsp, **yyolsp;
+char yysbuf[YYLMAX];
+char *yysptr = yysbuf;
+int *yyfnd;
+extern struct yysvf *yyestate;
+int yyprevious = YYNEWLINE;
+#if defined(__cplusplus) || defined(__STDC__)
+int yylook(void)
+#else
+yylook()
+#endif
+{
+ register struct yysvf *yystate, **lsp;
+ register struct yywork *yyt;
+ struct yysvf *yyz;
+ int yych, yyfirst;
+ struct yywork *yyr;
+# ifdef LEXDEBUG
+ int debug;
+# endif
+ char *yylastch;
+ /* start off machines */
+# ifdef LEXDEBUG
+ debug = 0;
+# endif
+ yyfirst=1;
+ if (!yymorfg)
+ yylastch = yytext;
+ else {
+ yymorfg=0;
+ yylastch = yytext+yyleng;
+ }
+ for(;;){
+ lsp = yylstate;
+ yyestate = yystate = yybgin;
+ if (yyprevious==YYNEWLINE) yystate++;
+ for (;;){
+# ifdef LEXDEBUG
+ if(debug)fprintf(yyout,"state %d\n",yystate-yysvec-1);
+# endif
+ yyt = yystate->yystoff;
+ if(yyt == yycrank && !yyfirst){ /* may not be any transitions */
+ yyz = yystate->yyother;
+ if(yyz == 0)break;
+ if(yyz->yystoff == yycrank)break;
+ }
+#ifndef __cplusplus
+ *yylastch++ = yych = input();
+#else
+ *yylastch++ = yych = lex_input();
+#endif
+ if(yylastch > &yytext[YYLMAX]) {
+ fprintf(yyout,"Input string too long, limit %d\n",YYLMAX);
+ exit(1);
+ }
+ yyfirst=0;
+ tryagain:
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"char ");
+ allprint(yych);
+ putchar('\n');
+ }
+# endif
+ yyr = yyt;
+ if ( (int)yyt > (int)yycrank){
+ yyt = yyr + yych;
+ if (yyt <= yytop && yyt->verify+yysvec == yystate){
+ if(yyt->advance+yysvec == YYLERR) /* error transitions */
+ {unput(*--yylastch);break;}
+ *lsp++ = yystate = yyt->advance+yysvec;
+ if(lsp > &yylstate[YYLMAX]) {
+ fprintf(yyout,"Input string too long, limit %d\n",YYLMAX);
+ exit(1);
+ }
+ goto contin;
+ }
+ }
+# ifdef YYOPTIM
+ else if((int)yyt < (int)yycrank) { /* r < yycrank */
+ yyt = yyr = yycrank+(yycrank-yyt);
+# ifdef LEXDEBUG
+ if(debug)fprintf(yyout,"compressed state\n");
+# endif
+ yyt = yyt + yych;
+ if(yyt <= yytop && yyt->verify+yysvec == yystate){
+ if(yyt->advance+yysvec == YYLERR) /* error transitions */
+ {unput(*--yylastch);break;}
+ *lsp++ = yystate = yyt->advance+yysvec;
+ if(lsp > &yylstate[YYLMAX]) {
+ fprintf(yyout,"Input string too long, limit %d\n",YYLMAX);
+ exit(1);
+ }
+ goto contin;
+ }
+ yyt = yyr + YYU(yymatch[yych]);
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"try fall back character ");
+ allprint(YYU(yymatch[yych]));
+ putchar('\n');
+ }
+# endif
+ if(yyt <= yytop && yyt->verify+yysvec == yystate){
+ if(yyt->advance+yysvec == YYLERR) /* error transition */
+ {unput(*--yylastch);break;}
+ *lsp++ = yystate = yyt->advance+yysvec;
+ if(lsp > &yylstate[YYLMAX]) {
+ fprintf(yyout,"Input string too long, limit %d\n",YYLMAX);
+ exit(1);
+ }
+ goto contin;
+ }
+ }
+ if ((yystate = yystate->yyother) && (yyt= yystate->yystoff) != yycrank){
+# ifdef LEXDEBUG
+ if(debug)fprintf(yyout,"fall back to state %d\n",yystate-yysvec-1);
+# endif
+ goto tryagain;
+ }
+# endif
+ else
+ {unput(*--yylastch);break;}
+ contin:
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"state %d char ",yystate-yysvec-1);
+ allprint(yych);
+ putchar('\n');
+ }
+# endif
+ ;
+ }
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"stopped at %d with ",*(lsp-1)-yysvec-1);
+ allprint(yych);
+ putchar('\n');
+ }
+# endif
+ while (lsp-- > yylstate){
+ *yylastch-- = 0;
+ if (*lsp != 0 && (yyfnd= (*lsp)->yystops) && *yyfnd > 0){
+ yyolsp = lsp;
+ if(yyextra[*yyfnd]){ /* must backup */
+ while(yyback((*lsp)->yystops,-*yyfnd) != 1 && lsp > yylstate){
+ lsp--;
+ unput(*yylastch--);
+ }
+ }
+ yyprevious = YYU(*yylastch);
+ yylsp = lsp;
+ yyleng = yylastch-yytext+1;
+ yytext[yyleng] = 0;
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"\nmatch ");
+ sprint(yytext);
+ fprintf(yyout," action %d\n",*yyfnd);
+ }
+# endif
+ return(*yyfnd++);
+ }
+ unput(*yylastch);
+ }
+ if (yytext[0] == 0 /* && feof(yyin) */)
+ {
+ yysptr=yysbuf;
+ return(0);
+ }
+#ifndef __cplusplus
+ yyprevious = yytext[0] = input();
+ if (yyprevious>0)
+ output(yyprevious);
+#else
+ yyprevious = yytext[0] = lex_input();
+ if (yyprevious>0)
+ lex_output(yyprevious);
+#endif
+ yylastch=yytext;
+# ifdef LEXDEBUG
+ if(debug)putchar('\n');
+# endif
+ }
+ }
+#if defined(__cplusplus) || defined(__STDC__)
+int yyback(int *p, int m)
+#else
+yyback(p, m)
+ int *p;
+#endif
+{
+ if (p==0) return(0);
+ while (*p) {
+ if (*p++ == m)
+ return(1);
+ }
+ return(0);
+}
+ /* the following are only used in the lex library */
+#if defined(__cplusplus) || defined(__STDC__)
+int yyinput(void)
+#else
+yyinput()
+#endif
+{
+#ifndef __cplusplus
+ return(input());
+#else
+ return(lex_input());
+#endif
+ }
+#if defined(__cplusplus) || defined(__STDC__)
+void yyoutput(int c)
+#else
+yyoutput(c)
+ int c;
+#endif
+{
+#ifndef __cplusplus
+ output(c);
+#else
+ lex_output(c);
+#endif
+ }
+#if defined(__cplusplus) || defined(__STDC__)
+void yyunput(int c)
+#else
+yyunput(c)
+ int c;
+#endif
+{
+ unput(c);
+ }
diff --git a/lib/libaccess/winnt.v b/lib/libaccess/winnt.v
new file mode 100644
index 00000000..9fea3453
--- /dev/null
+++ b/lib/libaccess/winnt.v
@@ -0,0 +1,156 @@
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef _VALUES_H
+#define _VALUES_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * These values work with any binary representation of integers
+ * where the high-order bit contains the sign.
+ */
+
+/* a number used normally for size of a shift */
+#define BITSPERBYTE 8
+
+#define BITS(type) (BITSPERBYTE * (int)sizeof (type))
+
+/* short, regular and long ints with only the high-order bit turned on */
+#define HIBITS ((short)(1 << BITS(short) - 1))
+
+#if defined(__STDC__)
+
+#define HIBITI (1U << BITS(int) - 1)
+#define HIBITL (1UL << BITS(long) - 1)
+
+#else
+
+#define HIBITI ((unsigned)1 << BITS(int) - 1)
+#define HIBITL (1L << BITS(long) - 1)
+
+#endif
+
+/* largest short, regular and long int */
+#define MAXSHORT ((short)~HIBITS)
+#define MAXINT ((int)(~HIBITI))
+#define MAXLONG ((long)(~HIBITL))
+
+/*
+ * various values that describe the binary floating-point representation
+ * _EXPBASE - the exponent base
+ * DMAXEXP - the maximum exponent of a double (as returned by frexp())
+ * FMAXEXP - the maximum exponent of a float (as returned by frexp())
+ * DMINEXP - the minimum exponent of a double (as returned by frexp())
+ * FMINEXP - the minimum exponent of a float (as returned by frexp())
+ * MAXDOUBLE - the largest double
+ * ((_EXPBASE ** DMAXEXP) * (1 - (_EXPBASE ** -DSIGNIF)))
+ * MAXFLOAT - the largest float
+ * ((_EXPBASE ** FMAXEXP) * (1 - (_EXPBASE ** -FSIGNIF)))
+ * MINDOUBLE - the smallest double (_EXPBASE ** (DMINEXP - 1))
+ * MINFLOAT - the smallest float (_EXPBASE ** (FMINEXP - 1))
+ * DSIGNIF - the number of significant bits in a double
+ * FSIGNIF - the number of significant bits in a float
+ * DMAXPOWTWO - the largest power of two exactly representable as a double
+ * FMAXPOWTWO - the largest power of two exactly representable as a float
+ * _IEEE - 1 if IEEE standard representation is used
+ * _DEXPLEN - the number of bits for the exponent of a double
+ * _FEXPLEN - the number of bits for the exponent of a float
+ * _HIDDENBIT - 1 if high-significance bit of mantissa is implicit
+ * LN_MAXDOUBLE - the natural log of the largest double -- log(MAXDOUBLE)
+ * LN_MINDOUBLE - the natural log of the smallest double -- log(MINDOUBLE)
+ * LN_MAXFLOAT - the natural log of the largest float -- log(MAXFLOAT)
+ * LN_MINFLOAT - the natural log of the smallest float -- log(MINFLOAT)
+ */
+
+#if defined(__STDC__)
+
+/*
+ * Note that the following construct, "!#machine(name)", is a non-standard
+ * extension to ANSI-C. It is maintained here to provide compatibility
+ * for existing compilations systems, but should be viewed as transitional
+ * and may be removed in a future release. If it is required that this
+ * file not contain this extension, edit this file to remove the offending
+ * condition.
+ *
+ * These machines are all IEEE-754:
+ */
+#if #machine(i386) || defined(__i386) || #machine(sparc) || defined(__sparc)
+#define MAXDOUBLE 1.79769313486231570e+308
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+#define MINDOUBLE 4.94065645841246544e-324
+#define MINFLOAT ((float)1.40129846432481707e-45)
+#define _IEEE 1
+#define _DEXPLEN 11
+#define _HIDDENBIT 1
+#define _LENBASE 1
+#define DMINEXP (-(DMAXEXP + DSIGNIF - _HIDDENBIT - 3))
+#define FMINEXP (-(FMAXEXP + FSIGNIF - _HIDDENBIT - 3))
+#else
+#error ISA not supported
+#endif
+
+#else
+
+/*
+ * These machines are all IEEE-754:
+ */
+#if defined(i386) || defined(__i386) || defined(sparc) || defined(__sparc)
+#define MAXDOUBLE 1.79769313486231570e+308
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+#define MINDOUBLE 4.94065645841246544e-324
+#define MINFLOAT ((float)1.40129846432481707e-45)
+#define _IEEE 1
+#define _DEXPLEN 11
+#define _HIDDENBIT 1
+#define _LENBASE 1
+#define DMINEXP (-(DMAXEXP + DSIGNIF - _HIDDENBIT - 3))
+#define FMINEXP (-(FMAXEXP + FSIGNIF - _HIDDENBIT - 3))
+#else
+/* #error is strictly ansi-C, but works as well as anything for K&R systems. */
+/*#error ISA not supported */
+#endif
+
+#endif /* __STDC__ */
+
+#define _EXPBASE (1 << _LENBASE)
+#define _FEXPLEN 8
+#define DSIGNIF (BITS(double) - _DEXPLEN + _HIDDENBIT - 1)
+#define FSIGNIF (BITS(float) - _FEXPLEN + _HIDDENBIT - 1)
+#define DMAXPOWTWO ((double)(1L << BITS(long) - 2) * \
+ (1L << DSIGNIF - BITS(long) + 1))
+#define FMAXPOWTWO ((float)(1L << FSIGNIF - 1))
+#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
+#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
+#define LN_MAXDOUBLE (M_LN2 * DMAXEXP)
+#define LN_MAXFLOAT (float)(M_LN2 * FMAXEXP)
+#define LN_MINDOUBLE (M_LN2 * (DMINEXP - 1))
+#define LN_MINFLOAT (float)(M_LN2 * (FMINEXP - 1))
+#define H_PREC (DSIGNIF % 2 ? (1L << DSIGNIF/2) * M_SQRT2 : 1L << DSIGNIF/2)
+#define FH_PREC \
+ (float)(FSIGNIF % 2 ? (1L << FSIGNIF/2) * M_SQRT2 : 1L << FSIGNIF/2)
+#define X_EPS (1.0/H_PREC)
+#define FX_EPS (float)((float)1.0/FH_PREC)
+#define X_PLOSS ((double)(long)(M_PI * H_PREC))
+#define FX_PLOSS ((float)(long)(M_PI * FH_PREC))
+#define X_TLOSS (M_PI * DMAXPOWTWO)
+#define FX_TLOSS (float)(M_PI * FMAXPOWTWO)
+#define M_LN2 0.69314718055994530942
+#define M_PI 3.14159265358979323846
+#define M_SQRT2 1.41421356237309504880
+#define MAXBEXP DMAXEXP /* for backward compatibility */
+#define MINBEXP DMINEXP /* for backward compatibility */
+#define MAXPOWTWO DMAXPOWTWO /* for backward compatibility */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VALUES_H */
diff --git a/lib/libaccess/winnt.y b/lib/libaccess/winnt.y
new file mode 100644
index 00000000..0ac06dfd
--- /dev/null
+++ b/lib/libaccess/winnt.y
@@ -0,0 +1,793 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "libaccess/ava.h"
+/*#include "libaccess/avapfile.h" */
+/* #include "netsite.h" */
+
+extern char *currFile;
+
+extern int linenum;
+extern char yytext[];
+
+static void AddDefType (int defType, char *defId);
+static void AddAVA (char* userID);
+
+void yyerror(const char* string);
+extern void logerror(const char* string,int num, char *file);
+
+AVAEntry tempEntry;
+AVATable entryTable;
+
+
+typedef union
+#ifdef __cplusplus
+ YYSTYPE
+#endif
+ {
+ char *string;
+ int num;
+} YYSTYPE;
+# define DEF_C 257
+# define DEF_CO 258
+# define DEF_OU 259
+# define DEF_CN 260
+# define EQ_SIGN 261
+# define DEF_START 262
+# define DEF_L 263
+# define DEF_E 264
+# define DEF_ST 265
+# define USER_ID 266
+# define DEF_ID 267
+
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#else
+#include <malloc.h>
+#include <memory.h>
+#endif
+
+#include <values.h>
+
+#ifdef __cplusplus
+
+#ifndef yyerror
+ void yyerror(const char *);
+#endif
+
+#ifndef yylex
+#ifdef __EXTERN_C__
+ extern "C" { int yylex(void); }
+#else
+ int yylex(void);
+#endif
+#endif
+ int yyparse(void);
+
+#endif
+#define yyclearin yychar = -1
+#define yyerrok yyerrflag = 0
+extern int yychar;
+extern int yyerrflag;
+YYSTYPE yylval;
+YYSTYPE yyval;
+typedef int yytabelem;
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 150
+#endif
+#if YYMAXDEPTH > 0
+int yy_yys[YYMAXDEPTH], *yys = yy_yys;
+YYSTYPE yy_yyv[YYMAXDEPTH], *yyv = yy_yyv;
+#else /* user does initial allocation */
+int *yys;
+YYSTYPE *yyv;
+#endif
+static int yymaxdepth = YYMAXDEPTH;
+# define YYERRCODE 256
+
+
+
+void yyerror(const char* string) {
+ logerror(string,linenum,currFile);
+}
+
+
+void AddDefType (int defType, char *defId) {
+ switch (defType) {
+ case DEF_C:
+ tempEntry.country = defId;
+ break;
+ case DEF_CO:
+ tempEntry.company = defId;
+ break;
+ case DEF_OU:
+ if (tempEntry.numOrgs % ORGS_ALLOCSIZE == 0) {
+ if (tempEntry.numOrgs == 0) {
+ tempEntry.organizations =
+ system_malloc_perm (sizeof (char*) * ORGS_ALLOCSIZE);
+ } else {
+ char **temp;
+ temp =
+ system_malloc_perm(sizeof(char*) * (tempEntry.numOrgs + ORGS_ALLOCSIZE));
+ memcpy (temp, tempEntry.organizations,
+ sizeof(char*)*tempEntry.numOrgs);
+ system_free_perm(tempEntry.organizations);
+ tempEntry.organizations = temp;
+ }
+ }
+ tempEntry.organizations[tempEntry.numOrgs++] = defId;
+ break;
+ case DEF_CN:
+ tempEntry.CNEntry = defId;
+ break;
+ case DEF_E:
+ tempEntry.email = defId;
+ break;
+ case DEF_L:
+ tempEntry.locality = defId;
+ break;
+ case DEF_ST:
+ tempEntry.state = defId;
+ break;
+ default:
+ break;
+ }
+}
+
+void AddAVA (char* userID) {
+ AVAEntry *newAVA;
+
+ newAVA = (AVAEntry*)system_malloc_perm(sizeof(AVAEntry));
+ if (!newAVA) {
+ yyerror ("Out of Memory in AddAVA");
+ return;
+ }
+ *newAVA = tempEntry;
+ newAVA->userid = userID;
+
+ _addAVAtoTable (newAVA, &entryTable);
+
+ tempEntry.CNEntry = tempEntry.userid = tempEntry.country = tempEntry.company = 0;
+ tempEntry.email = tempEntry.locality = tempEntry.state = NULL;
+ tempEntry.numOrgs = 0;
+}
+yytabelem yyexca[] ={
+-1, 1,
+ 0, -1,
+ -2, 0,
+ };
+# define YYNPROD 18
+# define YYLAST 19
+yytabelem yyact[]={
+
+ 10, 11, 12, 13, 19, 4, 14, 15, 16, 18,
+ 8, 3, 7, 6, 5, 2, 1, 9, 17 };
+yytabelem yypact[]={
+
+ -261,-10000000, -261,-10000000, -257,-10000000,-10000000, -257,-10000000, -252,
+-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000, -263,-10000000 };
+yytabelem yypgo[]={
+
+ 0, 17, 16, 15, 11, 13, 12, 10 };
+yytabelem yyr1[]={
+
+ 0, 2, 2, 3, 3, 4, 5, 5, 6, 6,
+ 7, 1, 1, 1, 1, 1, 1, 1 };
+yytabelem yyr2[]={
+
+ 0, 2, 0, 4, 2, 5, 2, 0, 4, 2,
+ 7, 3, 3, 3, 3, 3, 3, 3 };
+yytabelem yychk[]={
+
+-10000000, -2, -3, -4, 266, -4, -5, -6, -7, -1,
+ 257, 258, 259, 260, 263, 264, 265, -7, 261, 267 };
+yytabelem yydef[]={
+
+ 2, -2, 1, 4, 7, 3, 5, 6, 9, 0,
+ 11, 12, 13, 14, 15, 16, 17, 8, 0, 10 };
+typedef struct
+#ifdef __cplusplus
+ yytoktype
+#endif
+{ char *t_name; int t_val; } yytoktype;
+#ifndef YYDEBUG
+# define YYDEBUG 0 /* don't allow debugging */
+#endif
+
+#if YYDEBUG
+
+yytoktype yytoks[] =
+{
+ "DEF_C", 257,
+ "DEF_CO", 258,
+ "DEF_OU", 259,
+ "DEF_CN", 260,
+ "EQ_SIGN", 261,
+ "DEF_START", 262,
+ "DEF_L", 263,
+ "DEF_E", 264,
+ "DEF_ST", 265,
+ "USER_ID", 266,
+ "DEF_ID", 267,
+ "-unknown-", -1 /* ends search */
+};
+
+char * yyreds[] =
+{
+ "-no such reduction-",
+ "source : ava.database",
+ "source : /* empty */",
+ "ava.database : ava.database ava",
+ "ava.database : ava",
+ "ava : USER_ID definitions",
+ "definitions : definition.list",
+ "definitions : /* empty */",
+ "definition.list : definition.list definition",
+ "definition.list : definition",
+ "definition : def.type EQ_SIGN DEF_ID",
+ "def.type : DEF_C",
+ "def.type : DEF_CO",
+ "def.type : DEF_OU",
+ "def.type : DEF_CN",
+ "def.type : DEF_L",
+ "def.type : DEF_E",
+ "def.type : DEF_ST",
+};
+#endif /* YYDEBUG */
+
+
+/*
+** Skeleton parser driver for yacc output
+*/
+
+/*
+** yacc user known macros and defines
+*/
+#define YYERROR goto yyerrlab
+#define YYACCEPT return(0)
+#define YYABORT return(1)
+#define YYBACKUP( newtoken, newvalue )\
+{\
+ if ( yychar >= 0 || ( yyr2[ yytmp ] >> 1 ) != 1 )\
+ {\
+ yyerror( "syntax error - cannot backup" );\
+ goto yyerrlab;\
+ }\
+ yychar = newtoken;\
+ yystate = *yyps;\
+ yylval = newvalue;\
+ goto yynewstate;\
+}
+#define YYRECOVERING() (!!yyerrflag)
+#define YYNEW(type) system_malloc(sizeof(type) * yynewmax)
+#define YYCOPY(to, from, type) \
+ (type *) memcpy(to, (char *) from, yynewmax * sizeof(type))
+#define YYENLARGE( from, type) \
+ (type *) system_realloc((char *) from, yynewmax * sizeof(type))
+#ifndef YYDEBUG
+# define YYDEBUG 1 /* make debugging available */
+#endif
+
+/*
+** user known globals
+*/
+int yydebug; /* set to 1 to get debugging */
+
+/*
+** driver internal defines
+*/
+#define YYFLAG (-10000000)
+
+/*
+** global variables used by the parser
+*/
+YYSTYPE *yypv; /* top of value stack */
+int *yyps; /* top of state stack */
+
+int yystate; /* current state */
+int yytmp; /* extra var (lasts between blocks) */
+
+int yynerrs; /* number of errors */
+int yyerrflag; /* error recovery flag */
+int yychar; /* current input token number */
+
+
+
+#ifdef YYNMBCHARS
+#define YYLEX() yycvtok(yylex())
+/*
+** yycvtok - return a token if i is a wchar_t value that exceeds 255.
+** If i<255, i itself is the token. If i>255 but the neither
+** of the 30th or 31st bit is on, i is already a token.
+*/
+#if defined(__STDC__) || defined(__cplusplus)
+int yycvtok(int i)
+#else
+int yycvtok(i) int i;
+#endif
+{
+ int first = 0;
+ int last = YYNMBCHARS - 1;
+ int mid;
+ wchar_t j;
+
+ if(i&0x60000000){/*Must convert to a token. */
+ if( yymbchars[last].character < i ){
+ return i;/*Giving up*/
+ }
+ while ((last>=first)&&(first>=0)) {/*Binary search loop*/
+ mid = (first+last)/2;
+ j = yymbchars[mid].character;
+ if( j==i ){/*Found*/
+ return yymbchars[mid].tvalue;
+ }else if( j<i ){
+ first = mid + 1;
+ }else{
+ last = mid -1;
+ }
+ }
+ /*No entry in the table.*/
+ return i;/* Giving up.*/
+ }else{/* i is already a token. */
+ return i;
+ }
+}
+#else/*!YYNMBCHARS*/
+#define YYLEX() yylex()
+#endif/*!YYNMBCHARS*/
+
+/*
+** yyparse - return 0 if worked, 1 if syntax error not recovered from
+*/
+#if defined(__STDC__) || defined(__cplusplus)
+int yyparse(void)
+#else
+int yyparse()
+#endif
+{
+ register YYSTYPE *yypvt; /* top of value stack for $vars */
+
+#if defined(__cplusplus) || defined(lint)
+/*
+ hacks to please C++ and lint - goto's inside switch should never be
+ executed; yypvt is set to 0 to avoid "used before set" warning.
+*/
+ static int __yaccpar_lint_hack__ = 0;
+ switch (__yaccpar_lint_hack__)
+ {
+ case 1: goto yyerrlab;
+ case 2: goto yynewstate;
+ }
+ yypvt = 0;
+#endif
+
+ /*
+ ** Initialize externals - yyparse may be called more than once
+ */
+ yypv = &yyv[-1];
+ yyps = &yys[-1];
+ yystate = 0;
+ yytmp = 0;
+ yynerrs = 0;
+ yyerrflag = 0;
+ yychar = -1;
+
+#if YYMAXDEPTH <= 0
+ if (yymaxdepth <= 0)
+ {
+ if ((yymaxdepth = YYEXPAND(0)) <= 0)
+ {
+ yyerror("yacc initialization error");
+ YYABORT;
+ }
+ }
+#endif
+
+ {
+ register YYSTYPE *yy_pv; /* top of value stack */
+ register int *yy_ps; /* top of state stack */
+ register int yy_state; /* current state */
+ register int yy_n; /* internal state number info */
+ goto yystack; /* moved from 6 lines above to here to please C++ */
+
+ /*
+ ** get globals into registers.
+ ** branch to here only if YYBACKUP was called.
+ */
+ yynewstate:
+ yy_pv = yypv;
+ yy_ps = yyps;
+ yy_state = yystate;
+ goto yy_newstate;
+
+ /*
+ ** get globals into registers.
+ ** either we just started, or we just finished a reduction
+ */
+ yystack:
+ yy_pv = yypv;
+ yy_ps = yyps;
+ yy_state = yystate;
+
+ /*
+ ** top of for (;;) loop while no reductions done
+ */
+ yy_stack:
+ /*
+ ** put a state and value onto the stacks
+ */
+#if YYDEBUG
+ /*
+ ** if debugging, look up token value in list of value vs.
+ ** name pairs. 0 and negative (-1) are special values.
+ ** Note: linear search is used since time is not a real
+ ** consideration while debugging.
+ */
+ if ( yydebug )
+ {
+ register int yy_i;
+
+ printf( "State %d, token ", yy_state );
+ if ( yychar == 0 )
+ printf( "end-of-file\n" );
+ else if ( yychar < 0 )
+ printf( "-none-\n" );
+ else
+ {
+ for ( yy_i = 0; yytoks[yy_i].t_val >= 0;
+ yy_i++ )
+ {
+ if ( yytoks[yy_i].t_val == yychar )
+ break;
+ }
+ printf( "%s\n", yytoks[yy_i].t_name );
+ }
+ }
+#endif /* YYDEBUG */
+ if ( ++yy_ps >= &yys[ yymaxdepth ] ) /* room on stack? */
+ {
+ /*
+ ** reallocate and recover. Note that pointers
+ ** have to be reset, or bad things will happen
+ */
+ int yyps_index = (yy_ps - yys);
+ int yypv_index = (yy_pv - yyv);
+ int yypvt_index = (yypvt - yyv);
+ int yynewmax;
+#ifdef YYEXPAND
+ yynewmax = YYEXPAND(yymaxdepth);
+#else
+ yynewmax = 2 * yymaxdepth; /* double table size */
+ if (yymaxdepth == YYMAXDEPTH) /* first time growth */
+ {
+ char *newyys = (char *)YYNEW(int);
+ char *newyyv = (char *)YYNEW(YYSTYPE);
+ if (newyys != 0 && newyyv != 0)
+ {
+ yys = YYCOPY(newyys, yys, int);
+ yyv = YYCOPY(newyyv, yyv, YYSTYPE);
+ }
+ else
+ yynewmax = 0; /* failed */
+ }
+ else /* not first time */
+ {
+ yys = YYENLARGE(yys, int);
+ yyv = YYENLARGE(yyv, YYSTYPE);
+ if (yys == 0 || yyv == 0)
+ yynewmax = 0; /* failed */
+ }
+#endif
+ if (yynewmax <= yymaxdepth) /* tables not expanded */
+ {
+ yyerror( "yacc stack overflow" );
+ YYABORT;
+ }
+ yymaxdepth = yynewmax;
+
+ yy_ps = yys + yyps_index;
+ yy_pv = yyv + yypv_index;
+ yypvt = yyv + yypvt_index;
+ }
+ *yy_ps = yy_state;
+ *++yy_pv = yyval;
+
+ /*
+ ** we have a new state - find out what to do
+ */
+ yy_newstate:
+ if ( ( yy_n = yypact[ yy_state ] ) <= YYFLAG )
+ goto yydefault; /* simple state */
+#if YYDEBUG
+ /*
+ ** if debugging, need to mark whether new token grabbed
+ */
+ yytmp = yychar < 0;
+#endif
+ if ( ( yychar < 0 ) && ( ( yychar = YYLEX() ) < 0 ) )
+ yychar = 0; /* reached EOF */
+#if YYDEBUG
+ if ( yydebug && yytmp )
+ {
+ register int yy_i;
+
+ printf( "Received token " );
+ if ( yychar == 0 )
+ printf( "end-of-file\n" );
+ else if ( yychar < 0 )
+ printf( "-none-\n" );
+ else
+ {
+ for ( yy_i = 0; yytoks[yy_i].t_val >= 0;
+ yy_i++ )
+ {
+ if ( yytoks[yy_i].t_val == yychar )
+ break;
+ }
+ printf( "%s\n", yytoks[yy_i].t_name );
+ }
+ }
+#endif /* YYDEBUG */
+ if ( ( ( yy_n += yychar ) < 0 ) || ( yy_n >= YYLAST ) )
+ goto yydefault;
+ if ( yychk[ yy_n = yyact[ yy_n ] ] == yychar ) /*valid shift*/
+ {
+ yychar = -1;
+ yyval = yylval;
+ yy_state = yy_n;
+ if ( yyerrflag > 0 )
+ yyerrflag--;
+ goto yy_stack;
+ }
+
+ yydefault:
+ if ( ( yy_n = yydef[ yy_state ] ) == -2 )
+ {
+#if YYDEBUG
+ yytmp = yychar < 0;
+#endif
+ if ( ( yychar < 0 ) && ( ( yychar = YYLEX() ) < 0 ) )
+ yychar = 0; /* reached EOF */
+#if YYDEBUG
+ if ( yydebug && yytmp )
+ {
+ register int yy_i;
+
+ printf( "Received token " );
+ if ( yychar == 0 )
+ printf( "end-of-file\n" );
+ else if ( yychar < 0 )
+ printf( "-none-\n" );
+ else
+ {
+ for ( yy_i = 0;
+ yytoks[yy_i].t_val >= 0;
+ yy_i++ )
+ {
+ if ( yytoks[yy_i].t_val
+ == yychar )
+ {
+ break;
+ }
+ }
+ printf( "%s\n", yytoks[yy_i].t_name );
+ }
+ }
+#endif /* YYDEBUG */
+ /*
+ ** look through exception table
+ */
+ {
+ register int *yyxi = yyexca;
+
+ while ( ( *yyxi != -1 ) ||
+ ( yyxi[1] != yy_state ) )
+ {
+ yyxi += 2;
+ }
+ while ( ( *(yyxi += 2) >= 0 ) &&
+ ( *yyxi != yychar ) )
+ ;
+ if ( ( yy_n = yyxi[1] ) < 0 )
+ YYACCEPT;
+ }
+ }
+
+ /*
+ ** check for syntax error
+ */
+ if ( yy_n == 0 ) /* have an error */
+ {
+ /* no worry about speed here! */
+ switch ( yyerrflag )
+ {
+ case 0: /* new error */
+ yyerror( "syntax error" );
+ goto skip_init;
+ yyerrlab:
+ /*
+ ** get globals into registers.
+ ** we have a user generated syntax type error
+ */
+ yy_pv = yypv;
+ yy_ps = yyps;
+ yy_state = yystate;
+ skip_init:
+ yynerrs++;
+ /* FALLTHRU */
+ case 1:
+ case 2: /* incompletely recovered error */
+ /* try again... */
+ yyerrflag = 3;
+ /*
+ ** find state where "error" is a legal
+ ** shift action
+ */
+ while ( yy_ps >= yys )
+ {
+ yy_n = yypact[ *yy_ps ] + YYERRCODE;
+ if ( yy_n >= 0 && yy_n < YYLAST &&
+ yychk[yyact[yy_n]] == YYERRCODE) {
+ /*
+ ** simulate shift of "error"
+ */
+ yy_state = yyact[ yy_n ];
+ goto yy_stack;
+ }
+ /*
+ ** current state has no shift on
+ ** "error", pop stack
+ */
+#if YYDEBUG
+# define _POP_ "Error recovery pops state %d, uncovers state %d\n"
+ if ( yydebug )
+ printf( _POP_, *yy_ps,
+ yy_ps[-1] );
+# undef _POP_
+#endif
+ yy_ps--;
+ yy_pv--;
+ }
+ /*
+ ** there is no state on stack with "error" as
+ ** a valid shift. give up.
+ */
+ YYABORT;
+ case 3: /* no shift yet; eat a token */
+#if YYDEBUG
+ /*
+ ** if debugging, look up token in list of
+ ** pairs. 0 and negative shouldn't occur,
+ ** but since timing doesn't matter when
+ ** debugging, it doesn't hurt to leave the
+ ** tests here.
+ */
+ if ( yydebug )
+ {
+ register int yy_i;
+
+ printf( "Error recovery discards " );
+ if ( yychar == 0 )
+ printf( "token end-of-file\n" );
+ else if ( yychar < 0 )
+ printf( "token -none-\n" );
+ else
+ {
+ for ( yy_i = 0;
+ yytoks[yy_i].t_val >= 0;
+ yy_i++ )
+ {
+ if ( yytoks[yy_i].t_val
+ == yychar )
+ {
+ break;
+ }
+ }
+ printf( "token %s\n",
+ yytoks[yy_i].t_name );
+ }
+ }
+#endif /* YYDEBUG */
+ if ( yychar == 0 ) /* reached EOF. quit */
+ YYABORT;
+ yychar = -1;
+ goto yy_newstate;
+ }
+ }/* end if ( yy_n == 0 ) */
+ /*
+ ** reduction by production yy_n
+ ** put stack tops, etc. so things right after switch
+ */
+#if YYDEBUG
+ /*
+ ** if debugging, print the string that is the user's
+ ** specification of the reduction which is just about
+ ** to be done.
+ */
+ if ( yydebug )
+ printf( "Reduce by (%d) \"%s\"\n",
+ yy_n, yyreds[ yy_n ] );
+#endif
+ yytmp = yy_n; /* value to switch over */
+ yypvt = yy_pv; /* $vars top of value stack */
+ /*
+ ** Look in goto table for next state
+ ** Sorry about using yy_state here as temporary
+ ** register variable, but why not, if it works...
+ ** If yyr2[ yy_n ] doesn't have the low order bit
+ ** set, then there is no action to be done for
+ ** this reduction. So, no saving & unsaving of
+ ** registers done. The only difference between the
+ ** code just after the if and the body of the if is
+ ** the goto yy_stack in the body. This way the test
+ ** can be made before the choice of what to do is needed.
+ */
+ {
+ /* length of production doubled with extra bit */
+ register int yy_len = yyr2[ yy_n ];
+
+ if ( !( yy_len & 01 ) )
+ {
+ yy_len >>= 1;
+ yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */
+ yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] +
+ *( yy_ps -= yy_len ) + 1;
+ if ( yy_state >= YYLAST ||
+ yychk[ yy_state =
+ yyact[ yy_state ] ] != -yy_n )
+ {
+ yy_state = yyact[ yypgo[ yy_n ] ];
+ }
+ goto yy_stack;
+ }
+ yy_len >>= 1;
+ yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */
+ yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] +
+ *( yy_ps -= yy_len ) + 1;
+ if ( yy_state >= YYLAST ||
+ yychk[ yy_state = yyact[ yy_state ] ] != -yy_n )
+ {
+ yy_state = yyact[ yypgo[ yy_n ] ];
+ }
+ }
+ /* save until reenter driver code */
+ yystate = yy_state;
+ yyps = yy_ps;
+ yypv = yy_pv;
+ }
+ /*
+ ** code supplied by user is placed in this switch
+ */
+ switch( yytmp )
+ {
+
+case 5:
+{AddAVA(yypvt[-1].string);} break;
+case 10:
+{AddDefType(yypvt[-2].num, yypvt[-0].string);} break;
+case 11:
+{yyval.num = DEF_C; } break;
+case 12:
+{yyval.num = DEF_CO;} break;
+case 13:
+{yyval.num = DEF_OU;} break;
+case 14:
+{yyval.num = DEF_CN;} break;
+case 15:
+{yyval.num = DEF_L; } break;
+case 16:
+{yyval.num = DEF_E; } break;
+case 17:
+{yyval.num = DEF_ST;} break;
+ }
+ goto yystack; /* reset registers in driver code */
+}
+
diff --git a/lib/libaccess/wintab.h b/lib/libaccess/wintab.h
new file mode 100644
index 00000000..b764cf78
--- /dev/null
+++ b/lib/libaccess/wintab.h
@@ -0,0 +1,26 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+typedef union
+#ifdef __cplusplus
+ YYSTYPE
+#endif
+ {
+ char *string;
+ int num;
+} YYSTYPE;
+extern YYSTYPE yylval;
+# define DEF_C 257
+# define DEF_CO 258
+# define DEF_OU 259
+# define DEF_CN 260
+# define EQ_SIGN 261
+# define DEF_START 262
+# define DEF_L 263
+# define DEF_E 264
+# define DEF_ST 265
+# define USER_ID 266
+# define DEF_ID 267
diff --git a/lib/libaccess/yy-sed b/lib/libaccess/yy-sed
new file mode 100644
index 00000000..24c4eaac
--- /dev/null
+++ b/lib/libaccess/yy-sed
@@ -0,0 +1,21 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+/#include <unistd.h>/d
+/#include <values.h>/d
+/#pragma ident/d
+s/malloc.h/netsite.h/g
+s/yyparse/acl_Parse/g
+s/yy_flex_alloc/ACL_FLEX_ALLOC/g
+s/yy_flex_realloc/ACL_FLEX_REALLOC/g
+s/yy_flex_free/ACL_FLEX_FREE/g
+s/malloc(/PERM_MALLOC(/g
+s/free(/PERM_FREE(/g
+s/realloc(/PERM_REALLOC(/g
+s/yy/acl/g
+s/YY/ACL/g
+s/lex.acl.c/acl.yy.cpp/g