OpenSolaris_b135/lib/libnisdb/ldap_parse.h

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#ifndef	_LDAP_PARSE_H
#define	_LDAP_PARSE_H

#include <lber.h>
#include <ldap.h>
#include <rpcsvc/nis.h>

#include "nis_hashitem.h"

/* Pick up N2L file names */
#include <ndbm.h>
#include "yptol/shim.h"
#include "yptol/yptol.h"

#ifdef	__cplusplus
extern "C" {
#endif

/*
 * New <ldap.h> doesn't define LDAP_SCOPE_UNKNOWN, but we still need it.
 */
#ifndef	LDAP_SCOPE_UNKNOWN
#define	LDAP_SCOPE_UNKNOWN	0xFF
#endif

/* Attribute/value hash list element */
typedef struct {
	__nis_hash_item_mt	item;		/* item.name is the attr name */
	int			numValues;
	char			**value;	/* Array of values */
	bool_t			isDefault;	/* True if value is a default */
} __nis_ldap_attribute_t;

/* YP Domains structure */
typedef struct {
	int	numDomains;	/* number of domains listed in mapping file */
	char	**domainLabels;	/* the labels for particular domain names */
	char	**domains;		/* Array of LDAP domains */
	int	numYppasswdd;	/* Number of yppasswddDomainLabels */
	char	**yppasswddDomainLabels;	/* yppasswdd domain labels */
} __yp_domain_context_t;

/*
 * Begin object mappings
 *
 * Note that the definitions, where necessary, proceed from the bottom
 * (i.e., the "atomic" components) up.
 */

/*
 * String match/print descriptor
 *
 * Intended for use together with a __nis_mapping_match_type_t, which will
 * determine which field of the union is valid.
 *
 * string	Pointer to a NUL-terminated string
 * single	Represents a single-character match such as '[a-bTe-w]',
 *		which would become
 *			{
 *				3,				numRange
 *				{'a', 'T', 'e'},		lo
 *				{'b', 'T', 'w'}			hi
 *			}
 *		Each pair lo[i]/hi[i] (0 <= i < numRange) defines the
 *		range of the wild-card match.
 * limit	No use currrently defined; will probably be removed
 * berString	Pointer to a string containing a single formatting
 *		character as defined by ber_printf(3LDAP). Example: "i"
 *		for a binary integer.
 */
typedef union {
	char				*string;
	struct {
		int		numRange;
		unsigned char	*lo;		/* Array of numRange elements */
		unsigned char	*hi;		/* Array of numRange elements */
	}				single;
	enum {
		bos,
		eos
	}				limit;
	char				*berString;
} __nis_mapping_match_t;

/*
 * String match/print types and descriptor
 *
 * Used to describe print or match conversions. The 'match' field has
 * the following interpretation:
 *
 * Type		__nis_mapping_match_t	Comment
 *
 * mmt_item		<unused>	Value as indicated by corresponding
 *					element in __nis_mapping_item_t or
 *					__nis_mapping_sub_element_t array
 * mmt_string		string
 * mmt_single		single
 * mmt_limit		limit		Probably not needed
 * mmt_any		<unused>	Match any number of any character
 * mmt_berstring	berString
 * mmt_begin		<unused>	Indicates beginning of format; optional
 * mmt_end		<unused>	Indicates end of format; REQUIRED to
 *					mark the end of an array of
 *					__nis_mapping_format_t's
 */
typedef enum {mmt_item, mmt_string, mmt_single, mmt_limit, mmt_any,
		mmt_berstring, mmt_begin, mmt_end}
	__nis_mapping_match_type_t;

typedef struct {
	__nis_mapping_match_type_t	type;
	__nis_mapping_match_t		match;
} __nis_mapping_format_t;

/* Forward */
struct __nis_mapping_element_struct;
struct __nis_mapping_item_struct;

/*
 * LDAP search triple
 *
 * Used to represent a search triple like
 *	ou=Group,?one?cn=staff
 * or
 *	ou=Group,?one?(&(cn=staff)(gidNumber=10))
 * or
 *	ou=Hosts,?one?("cn=%s", (cname, "%s.*"))
 *
 * base		The base DN; defaultSearchBase appended if 'base' ends with
 *		a comma.
 * scope	One of LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, or
 *		LDAP_SCOPE_SUBTREE; LDAP_SCOPE_UNKNOWN means that this
 *		__nis_search_triple_t is inactive
 * attrs	Either a filter, or a list of attribute/value pairs, depending
 *		on context.
 * element	Pointer to a value element. If 'element' is non-NULL, the
 *		'attrs' value is derived by evaluating 'element'.
 */
typedef struct {
	char					*base;
	int					scope;
	char					*attrs;
	struct __nis_mapping_element_struct	*element;
} __nis_search_triple_t;

/*
 * NIS+ index spec
 *
 * Represents a NIS+ index list, such as
 *	name=staff,gid=10
 *
 * numIndexes	The number of entries in the 'name'/'value' arrays
 * name		Array of column names
 * value	Array of column values; uses __nis_mapping_format_t so that
 *		wild-cards can be represented
 *
 * Example
 *		name=staff,gid=10
 *	2,						numIndexes
 *	{						name
 *		"name",
 *		"gid"
 *	},
 *	{						value
 *		{
 *			{mmt_begin},
 *			{mmt_string, "staff"},
 *			{mmt_end}
 *		},
 *		{
 *			{mmt_begin},
 *			{mmt_string, "gid"},
 *			{mmt_end}
 *		}
 *	}
 */
typedef struct {
	int			numIndexes;
	char			**name;
	__nis_mapping_format_t	**value;
} __nis_index_t;

/* What to do with the LDAP data when a NIS+ entry is deleted */
typedef enum {dd_always, dd_perDbId, dd_never} __nis_delete_disp_t;

/* Type of an element in a mapping rule */
typedef enum {me_item, me_print, me_split, me_match, me_extract}
	__nis_mapping_element_type_t;

/* Type of an item in a mapping rule */
typedef enum {mit_any, mit_nisplus, mit_ldap}	__nis_mapping_item_type_t;

/*
 * NIS+ object name, with index
 *
 * Used to represent a name like
 *	[name = staff, gid = 10]group.org_dir
 * (Note: spaces around "=" and after "," to make cstyle happy; such spaces
 * are not usually part of the syntax, but they are allowed.)
 *
 * index	The index part of the name. numIndexes == 0 means there is
 *		no index.
 * name		The object name proper. If it doesn't end in a dot, the
 *		nisplusLDAPbaseDomain is appended.
 */
typedef struct {
	__nis_index_t		index;
	char			*name;
} __nis_obj_spec_t;

/*
 * Complete representation of a subset of either the DIT or a NIS+ object.
 * Intended for use in a __nis_mapping_item_t, where the 'type' field
 * determines which field of the __nis_triple_or_obj_t is active.
 */
typedef union {
	__nis_search_triple_t	triple;
	__nis_obj_spec_t	obj;
} __nis_triple_or_obj_t;

/*
 * Mapping item
 *
 * The mapping item is a single LDAP attribute, or a NIS+ table column, such as
 *	ldap:gidNumber:ou=Group, ?one?cn=staff
 * or
 *	nisplus:gid[name = staff]group.org_dir
 * (Note: spaces around "=" and after "," to make cstyle happy; such spaces
 * are not usually part of the syntax, but they are allowed.)
 *
 * type		mit_ldap or mit_nisplus
 * name		Attribute/column name
 * searchSpec	LDAP search triple, or NIS+ indexed object name
 * repeat	True if item should be repeated if necessary. This is used
 *		to represent implied lists, such as '(memberUid)', which
 *		denotes all values of the 'memberUid' attribute.
 * exItem forward mapping item for supporting removespec syntax.
 *
 */
typedef struct __nis_mapping_item_struct {
	__nis_mapping_item_type_t	type;
	char				*name;
	__nis_triple_or_obj_t		searchSpec;
	bool_t				repeat;
	struct				__nis_mapping_item_struct	*exItem;
} __nis_mapping_item_t;

/*
 * Sub-element of a mapping rule element
 *
 * Each element/sub-element represents the value(s) derived according to
 * the semantics of the element. Although not explicitly represented here,
 * values are either strings or BER byte sequences.
 *
 * type			Type of the 'element' union
 * element.item		A single item
 * element.print	printf(3C)-style value
 *	fmt		Array of formatting elements, terminated by 'mmt_end'
 *	numItems	Number of items in the 'item' array
 *	item		Array of 'numItems' items
 *	doElide		Should the last character of the (string) value be
 *			removed ?
 *	elide		Character to be removed
 * element.split	Item value string split into multiple values
 *	item		A single item
 *	delim		The separator character for the split
 * element.extract	Extraction of a sub-string from an item value
 *	fmt		Array of formatting elements, terminated by 'mmt_end'
 *	item		A single item
 *
 * Examples (see __nis_mapping_element_t below for examples using the 'item'
 * field of __nis_mapping_sub_element_t). For notational convenience,
 * __nis_mapping_item_t's are shortened to just the item name.
 *
 * (1)	String value consisting of the string "{crypt}" followed by the
 *	value of the 'passwd' column. The NIS+LDAPmapping(4) representation
 *	is
 *		("{crypt}%s", passwd)
 *	and the element.print contains
 *		{					fmt
 *			{mmt_begin},
 *			{mmt_string, "{crypt}"},
 *			{mmt_item},
 *			{mmt_end}
 *		},
 *		1,					numItems
 *		{					item
 *			{"passwd"}
 *		}
 *		FALSE,					doElide
 *		'\0'					elide (unused)
 *
 * (2)	Split a value such as "member1,member2,member3" into multiple
 *	(three, here) values using ',' as the separator.
 *		(members, ",")
 *	element.split
 *		{"members"},				item
 *		','					delim
 *
 * (3)	Given a 'cname' column with the value "some.dom.ain.", extract
 *	"some", which becomes the value of the expression.
 *		(cname, "%s.*")
 *	element.extract
 *		{					fmt
 *			{mmt_begin},
 *			{mmt_item},
 *			{mmt_string, "."},
 *			{mmt_any},
 *			{mmt_end}
 *		},
 *		{"cname"}				item
 */
typedef struct {
	__nis_mapping_element_type_t				type;
	union {
		__nis_mapping_item_t				item;
		struct {
			__nis_mapping_format_t		*fmt;
			int				numItems;
			__nis_mapping_item_t		*item;
			bool_t				doElide;
			unsigned char			elide;
		}						print;
		struct {
			__nis_mapping_item_t		item;
			unsigned char			delim;
		}						split;
		struct {
			__nis_mapping_format_t		*fmt;
			__nis_mapping_item_t		item;
		}						extract;
	} element;
} __nis_mapping_sub_element_t;

/*
 * Mapping rule element
 *
 * Each element/sub-element represents the value(s) derived according to
 * the semantics of the element. Although not explicitly represented here,
 * values are either strings or BER byte sequences.
 *
 * type			Type of the 'element' union
 * element.item		A single item
 * element.print	printf(3C)-style value
 *	fmt		Array of formatting elements, terminated by 'mmt_end'
 *	numSubElements	Number of sub-elements in the 'subElement' array
 *	subElement	Array of 'numSubElements' sub-elements
 *	doElide		Should the last character of the (string) value(s) be
 *			removed ?
 *	elide		Character to be removed
 * element.split	Item value string split into multiple values
 *	item		A single item
 *	delim		The separator character for the split
 * element.match	Assignment of item values by matching to a format
 *	fmt		Array of formatting elements, terminated by 'mmt_end'
 *	numItems	Number of items in the 'item' array
 *	item		Array of 'numItems' items
 * element.extract	Extraction of a sub-string from an item value
 *	fmt		Array of formatting elements, terminated by 'mmt_end'
 *	item		A single item
 *
 * Examples; items represented by just the item name.
 *
 * (1)	The value of the 'name' column.
 *		name
 *	element.item
 *		{"name"}				item
 *
 * (2)	Example (1) for a sub-element showed how to construct a value from
 *	a printf(3C)-style format string and one or more item values.
 *	However that example is only valid when used as a sub-expression
 *	(in place of an item in a 'print' list, for example). If
 *		("{crypt}%s", passwd)
 *	was part of a rule like
 *		userPassword=("{crypt}%s", passwd)
 *	the representation would use a __nis_mapping_element_t as follows.
 *	element.print
 *		{					fmt
 *			{mmt_begin},
 *			{mmt_string, "{crypt}"},
 *			{mmt_item},
 *			{mmt_end}
 *		},
 *		1,					numSubElements
 *		{					subElement
 *			me_item,				type
 *			{"passwd"}				item
 *		},
 *		FALSE,					doElide
 *		'\0'					elide (unused)
 *
 * (3)	Match a value such as "{dh-1024}abcdef000234" to a template format
 *	"{%s}%s", assign "dh-1024" to the 'auth_type' column, and
 *	"abcdef000234" to the 'public_data' column.
 *		("{%s}%s", auth_type, public_data)
 *	element.match
 *		{					fmt
 *			{mmt_begin},
 *			{mmt_string, "{"},
 *			{mmt_item},
 *			{mmt_string, "}"},
 *			{mmt_item},
 *			{mmt_end}
 *		}
 *		2,					numItems
 *		{					item
 *			{"auth_type"},
 *			{"public_data"}
 *		}
 */
typedef struct __nis_mapping_element_struct {
	__nis_mapping_element_type_t				type;
	union {
		__nis_mapping_item_t				item;
		struct {
			__nis_mapping_format_t		*fmt;
			int				numSubElements;
			__nis_mapping_sub_element_t	*subElement;
			bool_t				doElide;
			unsigned char			elide;
		}						print;
		struct {
			__nis_mapping_item_t		item;
			unsigned char			delim;
		}						split;
		struct {
			__nis_mapping_format_t		*fmt;
			int				numItems;
			__nis_mapping_item_t		*item;
		}						match;
		struct {
			__nis_mapping_format_t		*fmt;
			__nis_mapping_item_t		item;
		}						extract;
	} element;
} __nis_mapping_element_t;

/*
 * One side (left or right) of a mapping rule
 *
 * Example
 *	The rule
 *		userPassword=("{crypt}%s", passwd)
 *	would be reprsented by a __nis_mapping_rule_t as follows
 *		{					lhs
 *			1,					numElements
 *			{					element
 *				me_item,
 *				{"userPassword"}
 *			}
 *		},
 *		{					rhs
 *			1,					numElements
 *			{					element
 *				me_print,
 *				{
 *						See example (2) under
 *						__nis_mapping_element_t
 *						above
 *				}
 *			}
 *		}
 */
typedef struct {
	int			numElements;
	__nis_mapping_element_t	*element;
} __nis_mapping_rlhs_t;

/* A single mapping rule: attribute -> column or column -> attribute */
typedef struct {
	__nis_mapping_rlhs_t	lhs;
	__nis_mapping_rlhs_t	rhs;
} __nis_mapping_rule_t;

/*
 * Map (sub-set of) NIS+ object to location(s) in the LDAP DB
 *
 * read		base/scope/filter triple used to read data from LDAP;
 *		LDAP_SCOPE_UNKNOWN indicates that 'read' is unused
 * write	base/scope/attrlist triple used to write data to LDAP;
 *		LDAP_SCOPE_UNKNOWN indicates that 'write' is unused
 * delDisp	What should happen to the LDAP entry when the corresponding
 *		NIS+ data is deleted.
 * dbIdName	The dbId for the delete rule set (if any)
 * numDbIds	The number of rules in the 'dbId' rule set
 * dbId		The delete rule set; this field must point to a valid
 *		rule set if 'delDisp' is 'dd_perDbId'; ignored otherwise
 * next		Pointer to the next __nis_object_dn_t structure for this
 *		NIS+ object.
 *
 * Example
 *	The "group.org_dir.x.y.z." NIS+ table should be read from and
 *	written to the "ou=Group" container at "dc=x,dc=y,dc=z". Upon
 *	NIS+ entry deletion, we should always attempt to delete the
 *	corresponding LDAP attributes.
 *
 *	{						read
 *		"ou=Group,dc=x,dc=y,dc=z",
 *		LDAP_SCOPE_ONELEVEL,
 *		"objectClass=posixGroup"
 *	},
 *	{						write
 *		"ou=Group,dc=x,dc=y,dc=z",
 *		LDAP_SCOPE_ONELEVEL,
 *		"objectClass=posixGroup"
 *	},
 *	dd_always,					delDisp
 *	NULL,						dbIdName
 *	0,
 *	NULL,						dbId
 *	NULL						next
 */
typedef struct {
	__nis_search_triple_t	read;
	__nis_search_triple_t	write;
	__nis_delete_disp_t	delDisp;
	char			*dbIdName;
	int			numDbIds;
	__nis_mapping_rule_t	**dbId;		/* Delete rule set */
	void			*next;
} __nis_object_dn_t;

/*
 * Per-dbId or -object mapping
 *
 * Initially collected per-dbId (so that item.name=dbId), the
 * __nis_table_mapping_t's are later stored per-object (whereupon
 * item.name=objName).
 *
 * item			Structure used by the hash_item functions
 * dbId			The dbId associated with the __nis_table_mapping_t
 *			structure
 * index		Object sub-set specification; only defined for
 *			tables; index.numIndexes equal to zero means that
 *			the 'index' is unused.
 * next			Pointer to next table sub-set, if any
 * numColumns	Number of columns if the object is a table
 * column		Column names
 * initTtlLo	Lower limit on the initial TTL
 * initTtlHi	Upper limit on the initial TTL
 * ttl			TTL set after refresh
 * commentChar	NIS map comment character
 * objectDN		Location in the LDAP DB
 * numSplits	number of split fields
 * separatorStr separator string to break up NIS split field attributes
 * usedns_flag  indicates if the -b option to makedbm is used for a map.
 * securemap_flag indicates if the -s option to makedbm is used for a map.
 * __nis_mapping_element_t Parsed format strings and name fields storage
 * numRulesFromLDAP	Number of rules (and hence elements in the
 *			'ruleFromLDAP' array) for mapping LDAP entries
 *			to NIS+ objects
 * ruleFromLDAP
 * numRulesToLDAP	Number of rules (and hence elements in the
 *			'ruleToLDAP' array) for mapping NIS+ objects to
 *			LDAP entries
 * ruleToLDAP
 * objType		The NIS+ object type; NIS_BOGUS_OBJ used to indicate
 *			not set (in which case the other object data fields
 *			should be assumed to be invalid)
 * objName		The fully qualified name of the NIS+ object
 * objPath		The name used internally by libnisdb (which
 *			is path to the data file for the table/directory
 *			containing the object)
 * obj			A copy of the object itself
 * isMaster		Set if this machine is the master for the object
 *			(actually for the directory containing it)
 * seq_num	A sequence number representing the order of the maps
 *			as listed in the NISLDAPmapping.template file.
 *
 * Example
 *	Map the subset of the NIS+ 'group.org_dir.x.y.z.' table for which
 *	is true that the 'name' starts with 'a' or 'o' to location per
 *	the __nis_object_dn_t example above. No translation rules.
 *
 *		{					item
 *			"group.org_dir.x.y.z."			name
 *			<omitted>
 *		},
 *		"group_subset",				dbId
 *		1,					numIndexes
 *		{					index
 *			1,
 *			{"name"},
 *			{
 *				{mmt_begin},
 *				{
 *					mmt_single,
 *					2,
 *					{'a', 'o'},
 *					{'a', 'o'},
 *				}
 *				{mmt_any},
 *				{mmt_end}
 *			}
 *		}
 *		NULL,					next
 *		4,					numColumns
 *		{					column
 *			"name",
 *			"passwd",
 *			"gid",
 *			"members"
 *		},
 *		1800,					initTtlLo
 *		5400,					initTtlHi
 *		3600,					ttl
 *		'#',					commentChar
 *		<see __nis_object_dn_t example>,	objectDN
 *		0,						numSplits
 *		NULL,					separatorStr
 *		0,						usedns_flag
 *		0, 						securemap_flag
 *		<see __nis_mapping_element_t example>, e
 *		0,					numRulesFromLDAP
 *		NULL,					ruleFromLDAP
 *		0,					numRulesToLDAP
 *		NULL					ruleToLDAP
 *		NIS_TABLE_OBJ,				objType
 *		"group.org_dir.x.y.z.",			objName
 *		"/var/nis/data/group.org_dir"		objPath
 *		<pointer to NIS+ object>		obj
 *		1					isMaster
 */
typedef struct {
	__nis_hash_item_mt	item;		/* item.name=dbId||objName */
	char			*dbId;		/* Used during initializaton */
	__nis_index_t		index;
	void			*next;		/* Next sub-set spec */
	void			*seqNext;	/* Next in config sequence */
	int				numColumns;
	char			**column;
	time_t			initTtlLo;
	time_t			initTtlHi;
	time_t			ttl;
	char			commentChar;
	__nis_object_dn_t	*objectDN;
	int				numSplits;
	char			*separatorStr;
	int				usedns_flag;
	int				securemap_flag;
	__nis_mapping_element_t	*e;
	int			numRulesFromLDAP;
	__nis_mapping_rule_t	**ruleFromLDAP;
	int			numRulesToLDAP;
	__nis_mapping_rule_t	**ruleToLDAP;
/*
 * The following fields contain information about the mapped object.
 */
	zotypes			objType;
	char			*objName;	/* FQ object name */
	char			*objPath;	/* nisdb's internal name */
	nis_object		*obj;		/* NIS+ object */
	int			isMaster;	/* Master for this object ? */
	int			seq_num;
} __nis_table_mapping_t;

/* End object mappings */

/* Default config file paths */
#define	DEFAULTCONFFILE	"/var/nis/NIS+LDAPmapping"
#define	ETCCONFFILE	"/etc/default/rpc.nisd"
#define	YP_DEFAULTCONFFILE	NTOL_MAP_FILE
#define	YP_ETCCONFFILE	NTOL_CONFIG_FILE

/* Path to the root object dir file */
#define	ROOTDIRFILE	"/var/nis/data/root_dir"
/* Path to the root object file */
#define	ROOTOBJFILE	"/var/nis/data/root.object"

extern __nis_table_mapping_t	*ldapMappingSeq;
extern int yp2ldap;

/* Exported functions */
int			parseConfig(char **ldapCLA, char *ldapConfFile);
int			linked2hash(__nis_table_mapping_t *tlist);
int			dbids2objs(__nis_hash_table_mt *objs,
				__nis_hash_table_mt *dbids);
void			__make_legal(char *s);
char			*internal_table_name(nis_name name, char *res);
nis_name		relative_name(char *s);
char			*internalTableName(char *name);
__nis_table_mapping_t	*getObjMapping(char *name, char *intNameArg,
				int asObj,
				int *doRead, int *doWrite);

#ifdef	__cplusplus
}
#endif	/* __cplusplus */

#endif	/* _LDAP_PARSE_H */