rewrite-int.h   [plain text]


/******************************************************************************
 *
 * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
 * All rights reserved.
 *
 * Permission is granted to anyone to use this software for any purpose
 * on any computer system, and to alter it and redistribute it, subject
 * to the following restrictions:
 *
 * 1. The author is not responsible for the consequences of use of this
 * software, no matter how awful, even if they arise from flaws in it.
 *
 * 2. The origin of this software must not be misrepresented, either by
 * explicit claim or by omission.  Since few users ever read sources,
 * credits should appear in the documentation.
 *
 * 3. Altered versions must be plainly marked as such, and must not be
 * misrepresented as being the original software.  Since few users
 * ever read sources, credits should appear in the documentation.
 * 
 * 4. This notice may not be removed or altered.
 *
 ******************************************************************************/

#ifndef REWRITE_INT_H
#define REWRITE_INT_H

/*
 * These are required by every file of the library, so they're included here
 */
#include <ac/stdlib.h>
#include <ac/string.h>
#include <ac/syslog.h>
#include <ac/regex.h>
#include <ac/socket.h>
#include <ac/unistd.h>
#include <ac/ctype.h>

#include <lber.h>
#include <ldap.h>
#include "../libldap/ldap-int.h"

#include <avl.h>

#include <rewrite.h>

/* Uncomment to use ldap pvt threads */
#define USE_REWRITE_LDAP_PVT_THREADS
#include <ldap_pvt_thread.h>

/*
 * For details, see RATIONALE.
 */

#define REWRITE_MAX_MATCH	11	/* 0: overall string; 1-9: submatches */
#define REWRITE_MAX_PASSES	100

/*
 * Submatch escape char
 */
/* the '\' conflicts with slapd.conf parsing */
/* #define REWRITE_SUBMATCH_ESCAPE			'\\' */
#define REWRITE_SUBMATCH_ESCAPE                 '%'

/*
 * REGEX flags
 */

#define REWRITE_FLAG_HONORCASE			'C'
#define REWRITE_FLAG_BASICREGEX			'R'

/*
 * Action flags
 */
#define REWRITE_FLAG_EXECONCE			':'
#define REWRITE_FLAG_STOP			'@'
#define REWRITE_FLAG_UNWILLING			'#'
#define REWRITE_FLAG_GOTO			'G'	/* requires an arg */
#define REWRITE_FLAG_IGNORE_ERR			'I'

/*
 * Map operators
 */
#define REWRITE_OPERATOR_SUBCONTEXT		'>'
#define REWRITE_OPERATOR_COMMAND		'|'
#define REWRITE_OPERATOR_VARIABLE_SET		'&'
#define REWRITE_OPERATOR_VARIABLE_GET		'*'
#define REWRITE_OPERATOR_PARAM_GET		'$'


/***********
 * PRIVATE *
 ***********/

/*
 * Action
 */
struct rewrite_action {
	struct rewrite_action          *la_next;
	
#define REWRITE_ACTION_STOP		0x0001
#define REWRITE_ACTION_UNWILLING	0x0002
#define REWRITE_ACTION_GOTO		0x0003
#define REWRITE_ACTION_IGNORE_ERR	0x0004
	int                             la_type;
	void                           *la_args;
};

/*
 * Map
 */
struct rewrite_map {

	/*
	 * Legacy stuff
	 */
#define REWRITE_MAP_XFILEMAP		0x0001	/* Rough implementation! */
#define REWRITE_MAP_XPWDMAP		0x0002  /* uid -> gecos */
#define REWRITE_MAP_XLDAPMAP		0x0003	/* Not implemented yet! */

	/*
	 * Maps with args
	 */
#define REWRITE_MAP_SUBCONTEXT		0x0101
	
#define REWRITE_MAP_SET_OP_VAR		0x0102
#define REWRITE_MAP_SETW_OP_VAR		0x0103
#define REWRITE_MAP_GET_OP_VAR		0x0104
#define	REWRITE_MAP_SET_SESN_VAR	0x0105
#define REWRITE_MAP_SETW_SESN_VAR	0x0106
#define	REWRITE_MAP_GET_SESN_VAR	0x0107
#define REWRITE_MAP_GET_PARAM		0x0108
#define REWRITE_MAP_BUILTIN		0x0109
	int                             lm_type;

	char                           *lm_name;
	void                           *lm_data;

	/*
	 * Old maps store private data in _lm_args;
	 * new maps store the substitution pattern in _lm_subst
	 */
	union {		
	        void                   *_lm_args;
		struct rewrite_subst   *_lm_subst;
	} lm_union;
#define	lm_args lm_union._lm_args
#define	lm_subst lm_union._lm_subst

#ifdef USE_REWRITE_LDAP_PVT_THREADS
	ldap_pvt_thread_mutex_t         lm_mutex;
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
};

/*
 * Builtin maps
 */
struct rewrite_builtin_map {
#define REWRITE_BUILTIN_MAP_LDAP	0x0201
	int                             lb_type;
	char                           *lb_name;
	void                           *lb_private;

#ifdef USE_REWRITE_LDAP_PVT_THREADS
	ldap_pvt_thread_mutex_t         lb_mutex;
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
};

/*
 * Submatch substitution
 */
struct rewrite_submatch {
#define REWRITE_SUBMATCH_ASIS		0x0000
#define REWRITE_SUBMATCH_XMAP		0x0001
#define REWRITE_SUBMATCH_MAP_W_ARG	0x0002
	int                             ls_type;
	struct rewrite_map             *ls_map;
	int                             ls_submatch;
	/*
	 * The first one represents the index of the submatch in case
	 * the map has single submatch as argument;
	 * the latter represents the map argument scheme in case
	 * the map has substitution string argument form
	 */
};

/*
 * Pattern substitution
 */
struct rewrite_subst {
	size_t                          lt_subs_len;
	struct berval                 **lt_subs;
	
	int                             lt_num_submatch;
	struct rewrite_submatch       **lt_submatch;
};

/*
 * Rule
 */
struct rewrite_rule {
	struct rewrite_rule            *lr_next;
	struct rewrite_rule            *lr_prev;

	char                           *lr_pattern;
	char                           *lr_subststring;
	char                           *lr_flagstring;
	regex_t                         lr_regex;

	/*
	 * I was thinking about some kind of per-rule mutex, but there's
	 * probably no need, because rules after compilation are only read;
	 * however, I need to check whether regexec is reentrant ...
	 */

	struct rewrite_subst           *lr_subst;
	
#define REWRITE_REGEX_ICASE		REG_ICASE
#define REWRITE_REGEX_EXTENDED		REG_EXTENDED	
	int                             lr_flags;

#define REWRITE_RECURSE			0x0001
#define REWRITE_EXEC_ONCE          	0x0002
	int				lr_mode;

	struct rewrite_action          *lr_action;
};

/*
 * Rewrite Context (set of rules)
 */
struct rewrite_context {
	char                           *lc_name;
	struct rewrite_context         *lc_alias;
	struct rewrite_rule            *lc_rule;
};

/*
 * Session
 */
struct rewrite_session {
	void                           *ls_cookie;
	Avlnode                        *ls_vars;
#ifdef USE_REWRITE_LDAP_PVT_THREADS
	ldap_pvt_thread_rdwr_t          ls_vars_mutex;
	ldap_pvt_thread_mutex_t		ls_mutex;
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
	int				ls_count;
};

/*
 * Variable
 */
struct rewrite_var {
	char                           *lv_name;
	struct berval                   lv_value;
};

/*
 * Operation
 */
struct rewrite_op {
	int                             lo_num_passes;
	int                             lo_depth;
	char                           *lo_string;
	char                           *lo_result;
	Avlnode                        *lo_vars;
	const void                     *lo_cookie;
};


/**********
 * PUBLIC *
 **********/

/*
 * Rewrite info
 */
struct rewrite_info {
	Avlnode                        *li_context;
	Avlnode                        *li_maps;
	/*
	 * No global mutex because maps are read only at 
	 * config time
	 */
	Avlnode                        *li_params;
	Avlnode                        *li_cookies;
	int                             li_num_cookies;

#ifdef USE_REWRITE_LDAP_PVT_THREADS
	ldap_pvt_thread_rdwr_t          li_params_mutex;
        ldap_pvt_thread_rdwr_t          li_cookies_mutex;
#endif /* USE_REWRITE_LDAP_PVT_THREADS */

	/*
	 * Default to `off';
	 * use `rewriteEngine {on|off}' directive to alter
	 */
	int				li_state;

	/*
	 * Defaults to REWRITE_MAXPASSES;
	 * use `rewriteMaxPasses numPasses' directive to alter
	 */
#define REWRITE_MAXPASSES		100
	int                             li_max_passes;

	/*
	 * Behavior in case a NULL or non-existent context is required
	 */
	int                             li_rewrite_mode;
};

/***********
 * PRIVATE *
 ***********/

LDAP_REWRITE_V (struct rewrite_context*) __curr_context;

/*
 * Maps
 */

/*
 * Parses a map (also in legacy 'x' version)
 */
LDAP_REWRITE_F (struct rewrite_map *)
rewrite_map_parse(
		struct rewrite_info *info,
		const char *s,
		const char **end
);

LDAP_REWRITE_F (struct rewrite_map *)
rewrite_xmap_parse(
		struct rewrite_info *info,
		const char *s,
		const char **end
);

/*
 * Resolves key in val by means of map (also in legacy 'x' version)
 */
LDAP_REWRITE_F (int)
rewrite_map_apply(
		struct rewrite_info *info,
		struct rewrite_op *op,
		struct rewrite_map *map,
		struct berval *key,
		struct berval *val
);

LDAP_REWRITE_F (int)
rewrite_xmap_apply(
		struct rewrite_info *info,
		struct rewrite_op *op,
		struct rewrite_map *map,
		struct berval *key,
		struct berval *val
);


/*
 * Submatch substitution
 */

/*
 * Compiles a substitution pattern
 */
LDAP_REWRITE_F (struct rewrite_subst *)
rewrite_subst_compile(
		struct rewrite_info *info,
		const char *result
);

/*
 * Substitutes a portion of rewritten string according to substitution
 * pattern using submatches
 */
LDAP_REWRITE_F (int)
rewrite_subst_apply(
		struct rewrite_info *info,
		struct rewrite_op *op,
		struct rewrite_subst *subst,
		const char *string,
		const regmatch_t *match,
		struct berval *val
);


/*
 * Rules
 */

/*
 * Compiles the rule and appends it at the running context
 */
LDAP_REWRITE_F (int)
rewrite_rule_compile(
		struct rewrite_info *info,
		struct rewrite_context *context,
		const char *pattern,
		const char *result,
		const char *flagstring
);

/*
 * Rewrites string according to rule; may return:
 *      REWRITE_REGEXEC_OK:	fine; if *result != NULL rule matched
 *      			and rewrite succeeded.
 *      REWRITE_REGEXEC_STOP:   fine, rule matched; stop processing
 *      			following rules
 *      REWRITE_REGEXEC_UNWILL: rule matched; force 'unwilling to perform'
 *      REWRITE_REGEXEC_ERR:	an error occurred
 */
LDAP_REWRITE_F (int)
rewrite_rule_apply(
		struct rewrite_info *info,
		struct rewrite_op *op,
		struct rewrite_rule *rule,
		const char *string,
		char **result
);

/*
 * Sessions
 */

/*
 * Fetches a struct rewrite_session
 */
LDAP_REWRITE_F (struct rewrite_session *)
rewrite_session_find(
                struct rewrite_info *info,
                const void *cookie
);

/*
 * Defines and inits a variable with session scope
 */
LDAP_REWRITE_F (int)
rewrite_session_var_set(
                struct rewrite_info *info,
                const void *cookie,
                const char *name,
                const char *value
);

/*
 * Gets a var with session scope
 */
LDAP_REWRITE_F (int)
rewrite_session_var_get(
                struct rewrite_info *info,
                const void *cookie,
                const char *name,
                struct berval *val
);

/*
 * Deletes a session
 */
LDAP_REWRITE_F (int)
rewrite_session_delete(
                struct rewrite_info *info,
                const void *cookie
);

/*
 * Destroys the cookie tree
 */
LDAP_REWRITE_F (int)
rewrite_session_destroy(
                struct rewrite_info *info
);


/*
 * Vars
 */

/*
 * Finds a var
 */
LDAP_REWRITE_F (struct rewrite_var *)
rewrite_var_find(
                Avlnode *tree,
                const char *name
);

/*
 * Inserts a newly created var
 */
LDAP_REWRITE_F (struct rewrite_var *)
rewrite_var_insert(
                Avlnode **tree,
                const char *name,
                const char *value
);

/*
 * Sets/inserts a var
 */
LDAP_REWRITE_F (struct rewrite_var *)
rewrite_var_set(
                Avlnode **tree,
                const char *name,
                const char *value,
                int insert
);

/*
 * Deletes a var tree
 */
LDAP_REWRITE_F (int)
rewrite_var_delete(
                Avlnode *tree
);


/*
 * Contexts
 */

/*
 * Finds the context named rewriteContext in the context tree
 */
LDAP_REWRITE_F (struct rewrite_context *)
rewrite_context_find(
		struct rewrite_info *info,
		const char *rewriteContext
);

/*
 * Creates a new context called rewriteContext and stores in into the tree
 */
LDAP_REWRITE_F (struct rewrite_context *)
rewrite_context_create(
		struct rewrite_info *info,
		const char *rewriteContext
);

/*
 * Rewrites string according to context; may return:
 *      OK:     fine; if *result != NULL rule matched and rewrite succeeded.
 *      STOP:   fine, rule matched; stop processing following rules
 *      UNWILL: rule matched; force 'unwilling to perform'
 */
LDAP_REWRITE_F (int)
rewrite_context_apply(
		struct rewrite_info *info,
		struct rewrite_op *op,
		struct rewrite_context *context,
		const char *string,
		char **result
);

#endif /* REWRITE_INT_H */