1/*	$NetBSD: stctrl.c,v 1.1.1.3 2010/12/12 15:21:37 adam Exp $	*/
2
3/* OpenLDAP: pkg/ldap/libraries/libldap/stctrl.c,v 1.3.2.5 2010/04/13 20:23:00 kurt Exp */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1998-2010 The OpenLDAP Foundation.
7 * Portions Copyright 2007 Pierangelo Masarati.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18/* ACKNOWLEDGEMENTS:
19 * This work was developed by Pierangelo Masarati for inclusion in
20 * OpenLDAP Software.
21 */
22
23#include "portable.h"
24
25#include <stdio.h>
26#include <ac/stdlib.h>
27#include <ac/string.h>
28#include <ac/time.h>
29
30#include "ldap-int.h"
31
32#ifdef LDAP_CONTROL_X_SESSION_TRACKING
33
34/*
35 * Client-side of <draft-wahl-ldap-session-03>
36 */
37
38int
39ldap_create_session_tracking_value(
40	LDAP		*ld,
41	char		*sessionSourceIp,
42	char		*sessionSourceName,
43	char		*formatOID,
44	struct berval	*sessionTrackingIdentifier,
45	struct berval	*value )
46{
47	BerElement	*ber = NULL;
48	ber_tag_t	tag;
49
50	struct berval	ip, name, oid, id;
51
52	if ( ld == NULL ||
53		formatOID == NULL ||
54		value == NULL )
55	{
56param_error:;
57		if ( ld ) {
58			ld->ld_errno = LDAP_PARAM_ERROR;
59		}
60
61		return LDAP_PARAM_ERROR;
62	}
63
64	assert( LDAP_VALID( ld ) );
65	ld->ld_errno = LDAP_SUCCESS;
66
67	/* check sizes according to I.D. */
68	if ( sessionSourceIp == NULL ) {
69		BER_BVSTR( &ip, "" );
70
71	} else {
72		ber_str2bv( sessionSourceIp, 0, 0, &ip );
73		/* NOTE: we're strict because we don't want
74		 * to send out bad data */
75		if ( ip.bv_len > 128 ) goto param_error;
76	}
77
78	if ( sessionSourceName == NULL ) {
79		BER_BVSTR( &name, "" );
80
81	} else {
82		ber_str2bv( sessionSourceName, 0, 0, &name );
83		/* NOTE: we're strict because we don't want
84		 * to send out bad data */
85		if ( name.bv_len > 65536 ) goto param_error;
86	}
87
88	ber_str2bv( formatOID, 0, 0, &oid );
89	/* NOTE: we're strict because we don't want
90	 * to send out bad data */
91	if ( oid.bv_len > 1024 ) goto param_error;
92
93	if ( sessionTrackingIdentifier == NULL ||
94		sessionTrackingIdentifier->bv_val == NULL )
95	{
96		BER_BVSTR( &id, "" );
97
98	} else {
99		id = *sessionTrackingIdentifier;
100	}
101
102	/* prepare value */
103	value->bv_val = NULL;
104	value->bv_len = 0;
105
106	ber = ldap_alloc_ber_with_options( ld );
107	if ( ber == NULL ) {
108		ld->ld_errno = LDAP_NO_MEMORY;
109		return ld->ld_errno;
110	}
111
112	tag = ber_printf( ber, "{OOOO}", &ip, &name, &oid, &id );
113	if ( tag == LBER_ERROR ) {
114		ld->ld_errno = LDAP_ENCODING_ERROR;
115		goto done;
116	}
117
118	if ( ber_flatten2( ber, value, 1 ) == -1 ) {
119		ld->ld_errno = LDAP_NO_MEMORY;
120	}
121
122done:;
123	if ( ber != NULL ) {
124		ber_free( ber, 1 );
125	}
126
127	return ld->ld_errno;
128}
129
130/*
131 * NOTE: this API is bad; it could be much more efficient...
132 */
133int
134ldap_create_session_tracking_control(
135	LDAP		*ld,
136	char		*sessionSourceIp,
137	char		*sessionSourceName,
138	char		*formatOID,
139	struct berval	*sessionTrackingIdentifier,
140	LDAPControl	**ctrlp )
141{
142	struct berval	value;
143
144	if ( ctrlp == NULL ) {
145		ld->ld_errno = LDAP_PARAM_ERROR;
146		return ld->ld_errno;
147	}
148
149	ld->ld_errno = ldap_create_session_tracking_value( ld,
150		sessionSourceIp, sessionSourceName, formatOID,
151		sessionTrackingIdentifier, &value );
152	if ( ld->ld_errno == LDAP_SUCCESS ) {
153		ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_SESSION_TRACKING,
154			0, &value, 0, ctrlp );
155		if ( ld->ld_errno != LDAP_SUCCESS ) {
156			LDAP_FREE( value.bv_val );
157		}
158	}
159
160	return ld->ld_errno;
161}
162
163int
164ldap_parse_session_tracking_control(
165	LDAP *ld,
166	LDAPControl *ctrl,
167	struct berval *ip,
168	struct berval *name,
169	struct berval *oid,
170	struct berval *id )
171{
172	BerElement	*ber;
173	ber_tag_t	tag;
174	ber_len_t	len;
175
176	if ( ld == NULL ||
177		ctrl == NULL ||
178		ip == NULL ||
179		name == NULL ||
180		oid == NULL ||
181		id == NULL )
182	{
183		if ( ld ) {
184			ld->ld_errno = LDAP_PARAM_ERROR;
185		}
186
187		/* NOTE: we want the caller to get all or nothing;
188		 * we could allow some of the pointers to be NULL,
189		 * if one does not want part of the data */
190		return LDAP_PARAM_ERROR;
191	}
192
193	BER_BVZERO( ip );
194	BER_BVZERO( name );
195	BER_BVZERO( oid );
196	BER_BVZERO( id );
197
198	ber = ber_init( &ctrl->ldctl_value );
199
200	if ( ber == NULL ) {
201		ld->ld_errno = LDAP_NO_MEMORY;
202		return ld->ld_errno;
203	}
204
205	tag = ber_skip_tag( ber, &len );
206	if ( tag != LBER_SEQUENCE ) {
207		tag = LBER_ERROR;
208		goto error;
209	}
210
211	/* sessionSourceIp */
212	tag = ber_peek_tag( ber, &len );
213	if ( tag == LBER_DEFAULT ) {
214		tag = LBER_ERROR;
215		goto error;
216	}
217
218	if ( len == 0 ) {
219		tag = ber_skip_tag( ber, &len );
220
221	} else {
222		if ( len > 128 ) {
223			/* should be LDAP_DECODING_ERROR,
224			 * but we're liberal in what we accept */
225		}
226		tag = ber_scanf( ber, "o", ip );
227	}
228
229	/* sessionSourceName */
230	tag = ber_peek_tag( ber, &len );
231	if ( tag == LBER_DEFAULT ) {
232		tag = LBER_ERROR;
233		goto error;
234	}
235
236	if ( len == 0 ) {
237		tag = ber_skip_tag( ber, &len );
238
239	} else {
240		if ( len > 65536 ) {
241			/* should be LDAP_DECODING_ERROR,
242			 * but we're liberal in what we accept */
243		}
244		tag = ber_scanf( ber, "o", name );
245	}
246
247	/* formatOID */
248	tag = ber_peek_tag( ber, &len );
249	if ( tag == LBER_DEFAULT ) {
250		tag = LBER_ERROR;
251		goto error;
252	}
253
254	if ( len == 0 ) {
255		ld->ld_errno = LDAP_DECODING_ERROR;
256		goto error;
257
258	} else {
259		if ( len > 1024 ) {
260			/* should be LDAP_DECODING_ERROR,
261			 * but we're liberal in what we accept */
262		}
263		tag = ber_scanf( ber, "o", oid );
264	}
265
266	/* FIXME: should check if it is an OID... leave it to the caller */
267
268	/* sessionTrackingIdentifier */
269	tag = ber_peek_tag( ber, &len );
270	if ( tag == LBER_DEFAULT ) {
271		tag = LBER_ERROR;
272		goto error;
273	}
274
275	if ( len == 0 ) {
276		tag = ber_skip_tag( ber, &len );
277
278	} else {
279#if 0
280		if ( len > 65536 ) {
281			/* should be LDAP_DECODING_ERROR,
282			 * but we're liberal in what we accept */
283		}
284#endif
285		tag = ber_scanf( ber, "o", id );
286	}
287
288	/* closure */
289	tag = ber_skip_tag( ber, &len );
290	if ( tag == LBER_DEFAULT && len == 0 ) {
291		tag = 0;
292	}
293
294error:;
295	(void)ber_free( ber, 1 );
296
297	if ( tag == LBER_ERROR ) {
298		return LDAP_DECODING_ERROR;
299	}
300
301	return ld->ld_errno;
302}
303
304#endif /* LDAP_CONTROL_X_SESSION_TRACKING */
305