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