137
* SASL encryption support for LBER Sockbufs
140
struct sb_sasl_data {
141
sasl_conn_t *sasl_context;
142
unsigned *sasl_maxbuf;
143
Sockbuf_Buf sec_buf_in;
149
sb_sasl_setup( Sockbuf_IO_Desc *sbiod, void *arg )
151
struct sb_sasl_data *p;
153
assert( sbiod != NULL );
155
p = LBER_MALLOC( sizeof( *p ) );
158
p->sasl_context = (sasl_conn_t *)arg;
159
ber_pvt_sb_buf_init( &p->sec_buf_in );
160
ber_pvt_sb_buf_init( &p->buf_in );
161
ber_pvt_sb_buf_init( &p->buf_out );
162
if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, SASL_MIN_BUFF_SIZE ) < 0 ) {
167
sasl_getprop( p->sasl_context, SASL_MAXOUTBUF,
168
(SASL_CONST void **)(char *) &p->sasl_maxbuf );
170
sbiod->sbiod_pvt = p;
176
sb_sasl_remove( Sockbuf_IO_Desc *sbiod )
178
struct sb_sasl_data *p;
180
assert( sbiod != NULL );
182
p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
138
struct sb_sasl_generic_data *p,
143
sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private;
146
sasl_getprop( sasl_context, SASL_MAXOUTBUF,
147
(SASL_CONST void **)(char *) &maxbuf );
149
*min_send = SASL_MIN_BUFF_SIZE;
151
*max_recv = SASL_MAX_BUFF_SIZE;
155
sb_sasl_cyrus_encode(
156
struct sb_sasl_generic_data *p,
161
sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private;
163
unsigned tmpsize = dst->buf_size;
165
ret = sasl_encode( sasl_context, (char *)buf, len,
166
(SASL_CONST char **)&dst->buf_base,
169
dst->buf_size = tmpsize;
170
dst->buf_end = dst->buf_size;
172
if ( ret != SASL_OK ) {
173
ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
174
"sb_sasl_cyrus_encode: failed to encode packet: %s\n",
175
sasl_errstring( ret, NULL, NULL ) );
183
sb_sasl_cyrus_decode(
184
struct sb_sasl_generic_data *p,
185
const Sockbuf_Buf *src,
188
sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private;
190
unsigned tmpsize = dst->buf_size;
192
ret = sasl_decode( sasl_context,
193
src->buf_base, src->buf_end,
194
(SASL_CONST char **)&dst->buf_base,
195
(unsigned *)&tmpsize );
198
dst->buf_size = tmpsize;
199
dst->buf_end = dst->buf_size;
201
if ( ret != SASL_OK ) {
202
ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
203
"sb_sasl_cyrus_decode: failed to decode packet: %s\n",
204
sasl_errstring( ret, NULL, NULL ) );
212
sb_sasl_cyrus_reset_buf(
213
struct sb_sasl_generic_data *p,
216
#if SASL_VERSION_MAJOR >= 2
217
ber_pvt_sb_buf_init( buf );
219
ber_pvt_sb_buf_destroy( buf );
225
struct sb_sasl_generic_data *p)
183
227
#if SASL_VERSION_MAJOR >= 2
185
229
* SASLv2 encode/decode buffers are managed by
188
232
p->buf_in.buf_base = NULL;
189
233
p->buf_out.buf_base = NULL;
191
ber_pvt_sb_buf_destroy( &p->sec_buf_in );
192
ber_pvt_sb_buf_destroy( &p->buf_in );
193
ber_pvt_sb_buf_destroy( &p->buf_out );
195
sbiod->sbiod_pvt = NULL;
200
sb_sasl_pkt_length( const unsigned char *buf, int debuglevel )
204
assert( buf != NULL );
211
if ( size > SASL_MAX_BUFF_SIZE ) {
212
/* somebody is trying to mess me up. */
213
ber_log_printf( LDAP_DEBUG_ANY, debuglevel,
214
"sb_sasl_pkt_length: received illegal packet length "
215
"of %lu bytes\n", (unsigned long)size );
216
size = 16; /* this should lead to an error. */
219
return size + 4; /* include the size !!! */
222
/* Drop a processed packet from the input buffer */
224
sb_sasl_drop_packet ( Sockbuf_Buf *sec_buf_in, int debuglevel )
228
len = sec_buf_in->buf_ptr - sec_buf_in->buf_end;
230
AC_MEMCPY( sec_buf_in->buf_base, sec_buf_in->buf_base +
231
sec_buf_in->buf_end, len );
234
sec_buf_in->buf_end = sb_sasl_pkt_length(
235
(unsigned char *) sec_buf_in->buf_base, debuglevel);
238
sec_buf_in->buf_end = 0;
240
sec_buf_in->buf_ptr = len;
244
sb_sasl_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
246
struct sb_sasl_data *p;
247
ber_slen_t ret, bufptr;
249
assert( sbiod != NULL );
250
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
252
p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
254
/* Are there anything left in the buffer? */
255
ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len );
262
#if SASL_VERSION_MAJOR >= 2
263
ber_pvt_sb_buf_init( &p->buf_in );
265
ber_pvt_sb_buf_destroy( &p->buf_in );
268
/* Read the length of the packet */
269
while ( p->sec_buf_in.buf_ptr < 4 ) {
270
ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
271
p->sec_buf_in.buf_ptr,
272
4 - p->sec_buf_in.buf_ptr );
274
if ( ( ret < 0 ) && ( errno == EINTR ) )
278
return bufptr ? bufptr : ret;
280
p->sec_buf_in.buf_ptr += ret;
283
/* The new packet always starts at p->sec_buf_in.buf_base */
284
ret = sb_sasl_pkt_length( (unsigned char *) p->sec_buf_in.buf_base,
285
sbiod->sbiod_sb->sb_debug );
287
/* Grow the packet buffer if neccessary */
288
if ( ( p->sec_buf_in.buf_size < (ber_len_t) ret ) &&
289
ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 )
294
p->sec_buf_in.buf_end = ret;
296
/* Did we read the whole encrypted packet? */
297
while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) {
298
/* No, we have got only a part of it */
299
ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr;
301
ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
302
p->sec_buf_in.buf_ptr, ret );
304
if ( ( ret < 0 ) && ( errno == EINTR ) )
308
return bufptr ? bufptr : ret;
310
p->sec_buf_in.buf_ptr += ret;
313
/* Decode the packet */
315
unsigned tmpsize = p->buf_in.buf_end;
316
ret = sasl_decode( p->sasl_context, p->sec_buf_in.buf_base,
317
p->sec_buf_in.buf_end,
318
(SASL_CONST char **)&p->buf_in.buf_base,
319
(unsigned *)&tmpsize );
320
p->buf_in.buf_end = tmpsize;
323
/* Drop the packet from the input buffer */
324
sb_sasl_drop_packet( &p->sec_buf_in, sbiod->sbiod_sb->sb_debug );
326
if ( ret != SASL_OK ) {
327
ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
328
"sb_sasl_read: failed to decode packet: %s\n",
329
sasl_errstring( ret, NULL, NULL ) );
334
p->buf_in.buf_size = p->buf_in.buf_end;
336
bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len );
342
sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
344
struct sb_sasl_data *p;
347
assert( sbiod != NULL );
348
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
350
p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
352
/* Are there anything left in the buffer? */
353
if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
354
ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
355
if ( ret < 0 ) return ret;
357
/* Still have something left?? */
358
if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
364
/* now encode the next packet. */
365
#if SASL_VERSION_MAJOR >= 2
366
ber_pvt_sb_buf_init( &p->buf_out );
368
ber_pvt_sb_buf_destroy( &p->buf_out );
370
if ( len > *p->sasl_maxbuf - 100 ) {
371
len = *p->sasl_maxbuf - 100; /* For safety margin */
375
unsigned tmpsize = p->buf_out.buf_size;
376
ret = sasl_encode( p->sasl_context, buf, len,
377
(SASL_CONST char **)&p->buf_out.buf_base,
379
p->buf_out.buf_size = tmpsize;
382
if ( ret != SASL_OK ) {
383
ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
384
"sb_sasl_write: failed to encode packet: %s\n",
385
sasl_errstring( ret, NULL, NULL ) );
389
p->buf_out.buf_end = p->buf_out.buf_size;
391
ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
393
/* return number of bytes encoded, not written, to ensure
394
* no byte is encoded twice (even if only sent once).
400
sb_sasl_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
402
struct sb_sasl_data *p;
404
p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
406
if ( opt == LBER_SB_OPT_DATA_READY ) {
407
if ( p->buf_in.buf_ptr != p->buf_in.buf_end ) return 1;
410
return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
413
Sockbuf_IO ldap_pvt_sockbuf_io_sasl = {
414
sb_sasl_setup, /* sbi_setup */
415
sb_sasl_remove, /* sbi_remove */
416
sb_sasl_ctrl, /* sbi_ctrl */
417
sb_sasl_read, /* sbi_read */
418
sb_sasl_write, /* sbi_write */
237
static const struct sb_sasl_generic_ops sb_sasl_cyrus_ops = {
239
sb_sasl_cyrus_encode,
240
sb_sasl_cyrus_decode,
241
sb_sasl_cyrus_reset_buf,
422
245
int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
424
Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_install\n",
427
/* don't install the stuff unless security has been negotiated */
429
if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO,
430
&ldap_pvt_sockbuf_io_sasl ) )
433
ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
434
LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_" );
436
ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl,
437
LBER_SBIOD_LEVEL_APPLICATION, ctx_arg );
247
struct sb_sasl_generic_install install_arg;
249
install_arg.ops = &sb_sasl_cyrus_ops;
250
install_arg.ops_private = ctx_arg;
252
return ldap_pvt_sasl_generic_install( sb, &install_arg );
443
255
void ldap_pvt_sasl_remove( Sockbuf *sb )
445
ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_sasl,
446
LBER_SBIOD_LEVEL_APPLICATION );
448
ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
449
LBER_SBIOD_LEVEL_APPLICATION );
257
ldap_pvt_sasl_generic_remove( sb );