1/* oidm.c - object identifier macro routines */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 1998-2011 The OpenLDAP Foundation.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16
17#include "portable.h"
18
19#include <stdio.h>
20
21#include <ac/ctype.h>
22#include <ac/string.h>
23#include <ac/socket.h>
24
25#include "slap.h"
26#include "lutil.h"
27#include "config.h"
28
29static LDAP_STAILQ_HEAD(OidMacroList, OidMacro) om_list
30	= LDAP_STAILQ_HEAD_INITIALIZER(om_list);
31
32OidMacro *om_sys_tail;
33
34/* Replace an OID Macro invocation with its full numeric OID.
35 * If the macro is used with "macroname:suffix" append ".suffix"
36 * to the expansion.
37 */
38char *
39oidm_find(char *oid)
40{
41	OidMacro *om;
42
43	/* OID macros must start alpha */
44	if ( OID_LEADCHAR( *oid ) )	{
45		return oid;
46	}
47
48	LDAP_STAILQ_FOREACH( om, &om_list, som_next ) {
49		BerVarray names = om->som_names;
50
51		if( names == NULL ) {
52			continue;
53		}
54
55		for( ; !BER_BVISNULL( names ) ; names++ ) {
56			int pos = dscompare(names->bv_val, oid, ':');
57
58			if( pos ) {
59				int suflen = strlen(oid + pos);
60				char *tmp = SLAP_MALLOC( om->som_oid.bv_len
61					+ suflen + 1);
62				if( tmp == NULL ) {
63					Debug( LDAP_DEBUG_ANY,
64						"oidm_find: SLAP_MALLOC failed", 0, 0, 0 );
65					return NULL;
66				}
67				strcpy(tmp, om->som_oid.bv_val);
68				if( suflen ) {
69					suflen = om->som_oid.bv_len;
70					tmp[suflen++] = '.';
71					strcpy(tmp+suflen, oid+pos+1);
72				}
73				return tmp;
74			}
75		}
76	}
77	return NULL;
78}
79
80void
81oidm_destroy()
82{
83	OidMacro *om;
84	while( !LDAP_STAILQ_EMPTY( &om_list )) {
85		om = LDAP_STAILQ_FIRST( &om_list );
86		LDAP_STAILQ_REMOVE_HEAD( &om_list, som_next );
87
88		ber_bvarray_free(om->som_names);
89		ber_bvarray_free(om->som_subs);
90		free(om->som_oid.bv_val);
91		free(om);
92
93	}
94}
95
96int
97parse_oidm(
98	struct config_args_s *c,
99	int		user,
100	OidMacro **rom)
101{
102	char *oid, *oidv;
103	OidMacro *om = NULL, *prev = NULL;
104	struct berval bv;
105
106	oidv = oidm_find( c->argv[2] );
107	if( !oidv ) {
108		snprintf( c->cr_msg, sizeof( c->cr_msg ),
109			"%s: OID %s not recognized",
110			c->argv[0], c->argv[2] );
111		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
112			"%s %s\n", c->log, c->cr_msg, 0 );
113		return 1;
114	}
115
116	oid = oidm_find( c->argv[1] );
117	if( oid != NULL ) {
118		int rc;
119		snprintf( c->cr_msg, sizeof( c->cr_msg ),
120			"%s: \"%s\" previously defined \"%s\"",
121			c->argv[0], c->argv[1], oid );
122		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
123			"%s %s\n", c->log, c->cr_msg, 0 );
124		/* Allow duplicate if the definition is identical */
125		rc = strcmp( oid, oidv ) != 0;
126		SLAP_FREE( oid );
127		if ( oidv != c->argv[2] )
128			SLAP_FREE( oidv );
129		return rc;
130	}
131
132	om = (OidMacro *) SLAP_CALLOC( sizeof(OidMacro), 1 );
133	if( om == NULL ) {
134		snprintf( c->cr_msg, sizeof( c->cr_msg ),
135			"%s: SLAP_CALLOC failed", c->argv[0] );
136		Debug( LDAP_DEBUG_ANY,
137			"%s %s\n", c->log, c->cr_msg, 0 );
138		if ( oidv != c->argv[2] )
139			SLAP_FREE( oidv );
140		return 1;
141	}
142
143	om->som_names = NULL;
144	om->som_subs = NULL;
145	ber_str2bv( c->argv[1], 0, 1, &bv );
146	ber_bvarray_add( &om->som_names, &bv );
147	ber_str2bv( c->argv[2], 0, 1, &bv );
148	ber_bvarray_add( &om->som_subs, &bv );
149	om->som_oid.bv_val = oidv;
150
151	if (om->som_oid.bv_val == c->argv[2]) {
152		om->som_oid.bv_val = ch_strdup( c->argv[2] );
153	}
154
155	om->som_oid.bv_len = strlen( om->som_oid.bv_val );
156	if ( !user ) {
157		om->som_flags |= SLAP_OM_HARDCODE;
158		prev = om_sys_tail;
159		om_sys_tail = om;
160	}
161
162	if ( prev ) {
163		LDAP_STAILQ_INSERT_AFTER( &om_list, prev, om, som_next );
164	} else {
165		LDAP_STAILQ_INSERT_TAIL( &om_list, om, som_next );
166	}
167	if ( rom ) *rom = om;
168	return 0;
169}
170
171void oidm_unparse( BerVarray *res, OidMacro *start, OidMacro *end, int sys )
172{
173	OidMacro *om;
174	int i, j, num;
175	struct berval *bva = NULL, idx;
176	char ibuf[32], *ptr;
177
178	if ( !start )
179		start = LDAP_STAILQ_FIRST( &om_list );
180
181	/* count the result size */
182	i = 0;
183	for ( om=start; om; om=LDAP_STAILQ_NEXT(om, som_next)) {
184		if ( sys && !(om->som_flags & SLAP_OM_HARDCODE)) break;
185		for ( j=0; !BER_BVISNULL(&om->som_names[j]); j++ );
186		i += j;
187		if ( om == end ) break;
188	}
189	num = i;
190	if (!i) return;
191
192	bva = ch_malloc( (num+1) * sizeof(struct berval) );
193	BER_BVZERO( bva+num );
194	idx.bv_val = ibuf;
195	if ( sys ) {
196		idx.bv_len = 0;
197		ibuf[0] = '\0';
198	}
199	for ( i=0,om=start; om; om=LDAP_STAILQ_NEXT(om, som_next)) {
200		if ( sys && !(om->som_flags & SLAP_OM_HARDCODE)) break;
201		for ( j=0; !BER_BVISNULL(&om->som_names[j]); i++,j++ ) {
202			if ( !sys ) {
203				idx.bv_len = sprintf(idx.bv_val, "{%d}", i );
204			}
205			bva[i].bv_len = idx.bv_len + om->som_names[j].bv_len +
206				om->som_subs[j].bv_len + 1;
207			bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
208			ptr = lutil_strcopy( bva[i].bv_val, ibuf );
209			ptr = lutil_strcopy( ptr, om->som_names[j].bv_val );
210			*ptr++ = ' ';
211			strcpy( ptr, om->som_subs[j].bv_val );
212		}
213		if ( i>=num ) break;
214		if ( om == end ) break;
215	}
216	*res = bva;
217}
218